envprobe 1.0.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.
package/src/scanner.js ADDED
@@ -0,0 +1,182 @@
1
+ /**
2
+ * File Scanner Module
3
+ *
4
+ * Recursively scans directories to find source files and detect environment variable references.
5
+ * Handles symlinks, permission errors, and integrates with ignore patterns.
6
+ *
7
+ * Requirements: 1.4.1-1.4.5
8
+ */
9
+
10
+ import fs from 'fs';
11
+ import path from 'path';
12
+ import { shouldIgnore } from './ignore.js';
13
+ import { normalizePath } from './utils.js';
14
+
15
+ /**
16
+ * Get supported file extensions for scanning
17
+ *
18
+ * @returns {string[]} Array of file extensions to scan
19
+ *
20
+ * Requirements: 1.4.2
21
+ */
22
+ export function getSupportedExtensions() {
23
+ return [
24
+ '.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs', // JavaScript/TypeScript
25
+ '.py', // Python
26
+ '.go', // Go
27
+ '.rb', // Ruby
28
+ '.rs', // Rust
29
+ '.sh', '.bash', '.zsh' // Shell/Bash
30
+ ];
31
+ }
32
+
33
+ /**
34
+ * Check if a file has a supported extension
35
+ *
36
+ * @param {string} filePath - Path to the file
37
+ * @returns {boolean} True if file extension is supported
38
+ *
39
+ * Requirements: 1.4.2
40
+ */
41
+ export function hasSupportedExtension(filePath) {
42
+ const ext = path.extname(filePath).toLowerCase();
43
+ return getSupportedExtensions().includes(ext);
44
+ }
45
+
46
+ /**
47
+ * Scan a directory recursively for source files
48
+ *
49
+ * @param {string} dirPath - Directory path to scan
50
+ * @param {string[]} ignorePatterns - Array of ignore patterns
51
+ * @param {Set<string>} visitedPaths - Set of visited paths (for symlink cycle detection)
52
+ * @returns {Promise<string[]>} Array of file paths to scan
53
+ *
54
+ * Preconditions:
55
+ * - dirPath is a valid directory path
56
+ * - ignorePatterns is a valid array (may be empty)
57
+ *
58
+ * Postconditions:
59
+ * - Returns array of all source files found
60
+ * - Excludes files matching ignore patterns
61
+ * - Handles symlink cycles without infinite loops
62
+ * - Continues on permission errors
63
+ *
64
+ * Requirements: 1.4.1, 1.4.3, 1.4.4, 1.4.5
65
+ */
66
+ export async function scanDirectory(dirPath, ignorePatterns = [], visitedPaths = new Set()) {
67
+ const files = [];
68
+ const normalizedDirPath = normalizePath(path.resolve(dirPath));
69
+
70
+ // Check if we've already visited this path (symlink cycle detection)
71
+ if (visitedPaths.has(normalizedDirPath)) {
72
+ return files;
73
+ }
74
+
75
+ visitedPaths.add(normalizedDirPath);
76
+
77
+ try {
78
+ const entries = await fs.promises.readdir(dirPath, { withFileTypes: true });
79
+
80
+ for (const entry of entries) {
81
+ const fullPath = path.join(dirPath, entry.name);
82
+ const relativePath = normalizePath(path.relative(process.cwd(), fullPath));
83
+
84
+ // Check if path should be ignored (check both full path and just the name)
85
+ if (shouldIgnore(relativePath, ignorePatterns) ||
86
+ shouldIgnore(entry.name, ignorePatterns) ||
87
+ shouldIgnore(relativePath + '/', ignorePatterns)) {
88
+ continue;
89
+ }
90
+
91
+ try {
92
+ let stats;
93
+
94
+ if (entry.isSymbolicLink()) {
95
+ // For symlinks, get stats of the target
96
+ try {
97
+ stats = await fs.promises.stat(fullPath);
98
+ } catch (error) {
99
+ // Broken symlink or permission denied - skip it
100
+ console.warn(`Warning: Cannot access symlink target: ${relativePath}`);
101
+ continue;
102
+ }
103
+ } else {
104
+ stats = entry;
105
+ }
106
+
107
+ if (stats.isDirectory()) {
108
+ // Recursively scan subdirectory
109
+ const subFiles = await scanDirectory(fullPath, ignorePatterns, visitedPaths);
110
+ files.push(...subFiles);
111
+ } else if (stats.isFile() && hasSupportedExtension(fullPath)) {
112
+ // Add file to list if it has a supported extension
113
+ files.push(fullPath);
114
+ }
115
+ } catch (error) {
116
+ // Permission denied or other error - log warning and continue
117
+ if (error.code === 'EACCES' || error.code === 'EPERM') {
118
+ console.warn(`Warning: Permission denied: ${relativePath}`);
119
+ } else {
120
+ console.warn(`Warning: Error accessing ${relativePath}: ${error.message}`);
121
+ }
122
+ continue;
123
+ }
124
+ }
125
+ } catch (error) {
126
+ // Directory read error - log warning and return what we have
127
+ if (error.code === 'EACCES' || error.code === 'EPERM') {
128
+ console.warn(`Warning: Permission denied: ${normalizedDirPath}`);
129
+ } else if (error.code === 'ENOENT') {
130
+ console.warn(`Warning: Directory not found: ${normalizedDirPath}`);
131
+ } else {
132
+ console.warn(`Warning: Error reading directory ${normalizedDirPath}: ${error.message}`);
133
+ }
134
+ }
135
+
136
+ return files;
137
+ }
138
+
139
+ /**
140
+ * Scan a single file or directory
141
+ *
142
+ * @param {string} targetPath - File or directory path to scan
143
+ * @param {string[]} ignorePatterns - Array of ignore patterns
144
+ * @returns {Promise<string[]>} Array of file paths to scan
145
+ *
146
+ * Preconditions:
147
+ * - targetPath exists and is readable
148
+ *
149
+ * Postconditions:
150
+ * - Returns array with single file if targetPath is a file
151
+ * - Returns array of all source files if targetPath is a directory
152
+ *
153
+ * Requirements: 1.4.1, 1.5.1
154
+ */
155
+ export async function scan(targetPath, ignorePatterns = []) {
156
+ try {
157
+ const stats = await fs.promises.stat(targetPath);
158
+
159
+ if (stats.isFile()) {
160
+ // Single file - return it if it has a supported extension
161
+ if (hasSupportedExtension(targetPath)) {
162
+ return [targetPath];
163
+ } else {
164
+ return [];
165
+ }
166
+ } else if (stats.isDirectory()) {
167
+ // Directory - scan recursively
168
+ return await scanDirectory(targetPath, ignorePatterns);
169
+ } else {
170
+ console.warn(`Warning: ${targetPath} is neither a file nor a directory`);
171
+ return [];
172
+ }
173
+ } catch (error) {
174
+ if (error.code === 'ENOENT') {
175
+ throw new Error(`Path not found: ${targetPath}`);
176
+ } else if (error.code === 'EACCES' || error.code === 'EPERM') {
177
+ throw new Error(`Permission denied: ${targetPath}`);
178
+ } else {
179
+ throw new Error(`Error accessing ${targetPath}: ${error.message}`);
180
+ }
181
+ }
182
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Go Scanner
3
+ * Detects environment variable references in Go files
4
+ * Supports: os.Getenv("VAR"), os.LookupEnv("VAR")
5
+ */
6
+
7
+ /**
8
+ * Regex patterns for detecting environment variable references
9
+ * Pattern 1: os.Getenv("VAR_NAME") - standard library function for getting env vars
10
+ * Pattern 2: os.LookupEnv("VAR_NAME") - returns value and boolean indicating if var exists
11
+ */
12
+ const PATTERNS = [
13
+ // os.Getenv("VAR_NAME") - standard way to get environment variables
14
+ /os\.Getenv\("([A-Z_][A-Z0-9_]*)"\)/g,
15
+
16
+ // os.LookupEnv("VAR_NAME") - returns (value, exists) tuple
17
+ /os\.LookupEnv\("([A-Z_][A-Z0-9_]*)"\)/g,
18
+ ];
19
+
20
+ /**
21
+ * Supported file extensions for Go
22
+ */
23
+ const SUPPORTED_EXTENSIONS = ['.go'];
24
+
25
+ /**
26
+ * Scan file content for environment variable references
27
+ * @param {string} content - File content to scan
28
+ * @param {string} filePath - Path to the file being scanned
29
+ * @returns {Array<{varName: string, filePath: string, lineNumber: number, pattern: string}>}
30
+ */
31
+ export function scan(content, filePath) {
32
+ const references = [];
33
+ const lines = content.split('\n');
34
+
35
+ for (let i = 0; i < lines.length; i++) {
36
+ references.push(...scanLine(lines[i], filePath, i + 1));
37
+ }
38
+
39
+ return references;
40
+ }
41
+
42
+ export function scanLine(line, filePath, lineNumber) {
43
+ const references = [];
44
+
45
+ for (const pattern of PATTERNS) {
46
+ pattern.lastIndex = 0;
47
+ let match;
48
+ while ((match = pattern.exec(line)) !== null) {
49
+ const varName = match[1];
50
+
51
+ if (varName && isValidEnvVarName(varName)) {
52
+ references.push({
53
+ varName,
54
+ filePath,
55
+ lineNumber,
56
+ pattern: match[0],
57
+ });
58
+ }
59
+ }
60
+ }
61
+
62
+ return references;
63
+ }
64
+
65
+ /**
66
+ * Validate environment variable name
67
+ * Must start with letter or underscore, contain only uppercase letters, digits, and underscores
68
+ * @param {string} varName - Variable name to validate
69
+ * @returns {boolean}
70
+ */
71
+ function isValidEnvVarName(varName) {
72
+ return /^[A-Z_][A-Z0-9_]*$/.test(varName);
73
+ }
74
+
75
+ /**
76
+ * Get supported file extensions
77
+ * @returns {string[]}
78
+ */
79
+ export function getSupportedExtensions() {
80
+ return SUPPORTED_EXTENSIONS;
81
+ }
82
+
83
+ /**
84
+ * Get regex patterns used for scanning
85
+ * @returns {RegExp[]}
86
+ */
87
+ export function getPatterns() {
88
+ return PATTERNS;
89
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * JavaScript/TypeScript Scanner
3
+ * Detects environment variable references in JS/TS files
4
+ * Supports: process.env.VAR, process.env['VAR'], import.meta.env.VAR
5
+ */
6
+
7
+ /**
8
+ * Regex patterns for detecting environment variable references
9
+ * Pattern 1: process.env.VAR_NAME (dot notation)
10
+ * Pattern 2: process.env['VAR_NAME'] or process.env["VAR_NAME"] (bracket notation)
11
+ * Pattern 3: import.meta.env.VAR_NAME (Vite/modern bundlers)
12
+ */
13
+ const PATTERNS = [
14
+ // Dot notation: process.env.VAR_NAME
15
+ /process\.env\.([A-Z_][A-Z0-9_]*)/g,
16
+
17
+ // Bracket notation: process.env['VAR_NAME'] or process.env["VAR_NAME"]
18
+ /process\.env\[['"]([A-Z_][A-Z0-9_]*)['"]]/g,
19
+
20
+ // Vite/modern bundlers: import.meta.env.VAR_NAME
21
+ /import\.meta\.env\.([A-Z_][A-Z0-9_]*)/g,
22
+ ];
23
+
24
+ /**
25
+ * Supported file extensions for JavaScript/TypeScript
26
+ */
27
+ const SUPPORTED_EXTENSIONS = ['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs'];
28
+
29
+ /**
30
+ * Scan file content for environment variable references
31
+ * @param {string} content - File content to scan
32
+ * @param {string} filePath - Path to the file being scanned
33
+ * @returns {Array<{varName: string, filePath: string, lineNumber: number, pattern: string}>}
34
+ */
35
+ export function scan(content, filePath) {
36
+ const references = [];
37
+ const lines = content.split('\n');
38
+
39
+ for (let i = 0; i < lines.length; i++) {
40
+ references.push(...scanLine(lines[i], filePath, i + 1));
41
+ }
42
+
43
+ return references;
44
+ }
45
+
46
+ export function scanLine(line, filePath, lineNumber) {
47
+ const references = [];
48
+
49
+ for (const pattern of PATTERNS) {
50
+ pattern.lastIndex = 0;
51
+ let match;
52
+ while ((match = pattern.exec(line)) !== null) {
53
+ const varName = match[1];
54
+
55
+ if (varName && isValidEnvVarName(varName)) {
56
+ references.push({
57
+ varName,
58
+ filePath,
59
+ lineNumber,
60
+ pattern: match[0],
61
+ });
62
+ }
63
+ }
64
+ }
65
+
66
+ return references;
67
+ }
68
+
69
+ /**
70
+ * Validate environment variable name
71
+ * Must start with letter or underscore, contain only uppercase letters, digits, and underscores
72
+ * @param {string} varName - Variable name to validate
73
+ * @returns {boolean}
74
+ */
75
+ function isValidEnvVarName(varName) {
76
+ return /^[A-Z_][A-Z0-9_]*$/.test(varName);
77
+ }
78
+
79
+ /**
80
+ * Get supported file extensions
81
+ * @returns {string[]}
82
+ */
83
+ export function getSupportedExtensions() {
84
+ return SUPPORTED_EXTENSIONS;
85
+ }
86
+
87
+ /**
88
+ * Get regex patterns used for scanning
89
+ * @returns {RegExp[]}
90
+ */
91
+ export function getPatterns() {
92
+ return PATTERNS;
93
+ }
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Python Scanner
3
+ * Detects environment variable references in Python files
4
+ * Supports: os.environ['VAR'], os.environ.get('VAR'), os.getenv('VAR')
5
+ */
6
+
7
+ /**
8
+ * Regex patterns for detecting environment variable references
9
+ * Pattern 1: os.environ['VAR_NAME'] or os.environ["VAR_NAME"] (bracket notation)
10
+ * Pattern 2: os.environ.get('VAR_NAME') or os.environ.get("VAR_NAME") (get method)
11
+ * Pattern 3: os.getenv('VAR_NAME') or os.getenv("VAR_NAME") (getenv function)
12
+ */
13
+ const PATTERNS = [
14
+ // Bracket notation: os.environ['VAR_NAME'] or os.environ["VAR_NAME"]
15
+ /os\.environ\[['"]([A-Z_][A-Z0-9_]*)['"]]/g,
16
+
17
+ // Get method: os.environ.get('VAR_NAME') or os.environ.get("VAR_NAME")
18
+ // Matches with or without default values: os.environ.get('VAR', 'default')
19
+ // The pattern captures up to and including the closing paren if no comma follows
20
+ /os\.environ\.get\(['"]([A-Z_][A-Z0-9_]*)['"](?:,.*?)?\)/g,
21
+
22
+ // Getenv function: os.getenv('VAR_NAME') or os.getenv("VAR_NAME")
23
+ // Matches with or without default values: os.getenv('VAR', 'default')
24
+ // The pattern captures up to and including the closing paren if no comma follows
25
+ /os\.getenv\(['"]([A-Z_][A-Z0-9_]*)['"](?:,.*?)?\)/g,
26
+ ];
27
+
28
+ /**
29
+ * Supported file extensions for Python
30
+ */
31
+ const SUPPORTED_EXTENSIONS = ['.py'];
32
+
33
+ /**
34
+ * Scan file content for environment variable references
35
+ * @param {string} content - File content to scan
36
+ * @param {string} filePath - Path to the file being scanned
37
+ * @returns {Array<{varName: string, filePath: string, lineNumber: number, pattern: string}>}
38
+ */
39
+ export function scan(content, filePath) {
40
+ const references = [];
41
+ const lines = content.split('\n');
42
+
43
+ for (let i = 0; i < lines.length; i++) {
44
+ references.push(...scanLine(lines[i], filePath, i + 1));
45
+ }
46
+
47
+ return references;
48
+ }
49
+
50
+ export function scanLine(line, filePath, lineNumber) {
51
+ const references = [];
52
+
53
+ for (const pattern of PATTERNS) {
54
+ pattern.lastIndex = 0;
55
+ let match;
56
+ while ((match = pattern.exec(line)) !== null) {
57
+ const varName = match[1];
58
+
59
+ if (varName && isValidEnvVarName(varName)) {
60
+ references.push({
61
+ varName,
62
+ filePath,
63
+ lineNumber,
64
+ pattern: match[0],
65
+ });
66
+ }
67
+ }
68
+ }
69
+
70
+ return references;
71
+ }
72
+
73
+ /**
74
+ * Validate environment variable name
75
+ * Must start with letter or underscore, contain only uppercase letters, digits, and underscores
76
+ * @param {string} varName - Variable name to validate
77
+ * @returns {boolean}
78
+ */
79
+ function isValidEnvVarName(varName) {
80
+ return /^[A-Z_][A-Z0-9_]*$/.test(varName);
81
+ }
82
+
83
+ /**
84
+ * Get supported file extensions
85
+ * @returns {string[]}
86
+ */
87
+ export function getSupportedExtensions() {
88
+ return SUPPORTED_EXTENSIONS;
89
+ }
90
+
91
+ /**
92
+ * Get regex patterns used for scanning
93
+ * @returns {RegExp[]}
94
+ */
95
+ export function getPatterns() {
96
+ return PATTERNS;
97
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Ruby Scanner
3
+ * Detects environment variable references in Ruby files
4
+ * Supports: ENV['VAR'], ENV.fetch('VAR')
5
+ */
6
+
7
+ /**
8
+ * Regex patterns for detecting environment variable references
9
+ * Pattern 1: ENV['VAR_NAME'] or ENV["VAR_NAME"] (bracket notation)
10
+ * Pattern 2: ENV.fetch('VAR_NAME') or ENV.fetch("VAR_NAME") (fetch method)
11
+ */
12
+ const PATTERNS = [
13
+ // Bracket notation: ENV['VAR_NAME'] or ENV["VAR_NAME"]
14
+ /ENV\[['"]([A-Z_][A-Z0-9_]*)['"]]/g,
15
+
16
+ // Fetch method: ENV.fetch('VAR_NAME') or ENV.fetch("VAR_NAME")
17
+ // Matches with or without default values: ENV.fetch('VAR', 'default')
18
+ /ENV\.fetch\(['"]([A-Z_][A-Z0-9_]*)['"](?:,.*?)?\)/g,
19
+ ];
20
+
21
+ /**
22
+ * Supported file extensions for Ruby
23
+ */
24
+ const SUPPORTED_EXTENSIONS = ['.rb'];
25
+
26
+ /**
27
+ * Scan file content for environment variable references
28
+ * @param {string} content - File content to scan
29
+ * @param {string} filePath - Path to the file being scanned
30
+ * @returns {Array<{varName: string, filePath: string, lineNumber: number, pattern: string}>}
31
+ */
32
+ export function scan(content, filePath) {
33
+ const references = [];
34
+ const lines = content.split('\n');
35
+
36
+ for (let i = 0; i < lines.length; i++) {
37
+ references.push(...scanLine(lines[i], filePath, i + 1));
38
+ }
39
+
40
+ return references;
41
+ }
42
+
43
+ export function scanLine(line, filePath, lineNumber) {
44
+ const references = [];
45
+
46
+ for (const pattern of PATTERNS) {
47
+ pattern.lastIndex = 0;
48
+ let match;
49
+ while ((match = pattern.exec(line)) !== null) {
50
+ const varName = match[1];
51
+
52
+ if (varName && isValidEnvVarName(varName)) {
53
+ references.push({
54
+ varName,
55
+ filePath,
56
+ lineNumber,
57
+ pattern: match[0],
58
+ });
59
+ }
60
+ }
61
+ }
62
+
63
+ return references;
64
+ }
65
+
66
+ /**
67
+ * Validate environment variable name
68
+ * Must start with letter or underscore, contain only uppercase letters, digits, and underscores
69
+ * @param {string} varName - Variable name to validate
70
+ * @returns {boolean}
71
+ */
72
+ function isValidEnvVarName(varName) {
73
+ return /^[A-Z_][A-Z0-9_]*$/.test(varName);
74
+ }
75
+
76
+ /**
77
+ * Get supported file extensions
78
+ * @returns {string[]}
79
+ */
80
+ export function getSupportedExtensions() {
81
+ return SUPPORTED_EXTENSIONS;
82
+ }
83
+
84
+ /**
85
+ * Get regex patterns used for scanning
86
+ * @returns {RegExp[]}
87
+ */
88
+ export function getPatterns() {
89
+ return PATTERNS;
90
+ }
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Rust Scanner
3
+ * Detects environment variable references in Rust files
4
+ * Supports: env::var("VAR"), std::env::var("VAR"), env::var_os("VAR"), std::env::var_os("VAR")
5
+ */
6
+
7
+ /**
8
+ * Regex patterns for detecting environment variable references
9
+ * Pattern 1: std::env::var("VAR_NAME") - full path form (returns Result<String>)
10
+ * Pattern 2: std::env::var_os("VAR_NAME") - full path form returning OsString (returns Option<OsString>)
11
+ * Pattern 3: env::var("VAR_NAME") - short form for getting env vars (returns Result<String>)
12
+ * Pattern 4: env::var_os("VAR_NAME") - short form returning OsString (returns Option<OsString>)
13
+ *
14
+ * Note: Order matters! We check std::env:: patterns first to avoid double-matching
15
+ * (since "env::var" would match within "std::env::var")
16
+ */
17
+ const PATTERNS = [
18
+ // std::env::var("VAR_NAME") - full path form, returns Result<String, VarError>
19
+ // Use negative lookbehind to ensure we don't match if preceded by non-whitespace (avoids matching "std::env::var")
20
+ /std::env::var\("([A-Z_][A-Z0-9_]*)"\)/g,
21
+
22
+ // std::env::var_os("VAR_NAME") - full path form, returns Option<OsString>
23
+ /std::env::var_os\("([A-Z_][A-Z0-9_]*)"\)/g,
24
+
25
+ // env::var("VAR_NAME") - short form, returns Result<String, VarError>
26
+ // Use negative lookbehind to ensure not preceded by "std::" to avoid double-matching
27
+ /(?<!std::)env::var\("([A-Z_][A-Z0-9_]*)"\)/g,
28
+
29
+ // env::var_os("VAR_NAME") - short form, returns Option<OsString>
30
+ // Use negative lookbehind to ensure not preceded by "std::" to avoid double-matching
31
+ /(?<!std::)env::var_os\("([A-Z_][A-Z0-9_]*)"\)/g,
32
+ ];
33
+
34
+ /**
35
+ * Supported file extensions for Rust
36
+ */
37
+ const SUPPORTED_EXTENSIONS = ['.rs'];
38
+
39
+ /**
40
+ * Scan file content for environment variable references
41
+ * @param {string} content - File content to scan
42
+ * @param {string} filePath - Path to the file being scanned
43
+ * @returns {Array<{varName: string, filePath: string, lineNumber: number, pattern: string}>}
44
+ */
45
+ export function scan(content, filePath) {
46
+ const references = [];
47
+ const lines = content.split('\n');
48
+
49
+ for (let i = 0; i < lines.length; i++) {
50
+ references.push(...scanLine(lines[i], filePath, i + 1));
51
+ }
52
+
53
+ return references;
54
+ }
55
+
56
+ export function scanLine(line, filePath, lineNumber) {
57
+ const references = [];
58
+
59
+ for (const pattern of PATTERNS) {
60
+ pattern.lastIndex = 0;
61
+ let match;
62
+ while ((match = pattern.exec(line)) !== null) {
63
+ const varName = match[1];
64
+
65
+ if (varName && isValidEnvVarName(varName)) {
66
+ references.push({
67
+ varName,
68
+ filePath,
69
+ lineNumber,
70
+ pattern: match[0],
71
+ });
72
+ }
73
+ }
74
+ }
75
+
76
+ return references;
77
+ }
78
+
79
+ /**
80
+ * Validate environment variable name
81
+ * Must start with letter or underscore, contain only uppercase letters, digits, and underscores
82
+ * @param {string} varName - Variable name to validate
83
+ * @returns {boolean}
84
+ */
85
+ function isValidEnvVarName(varName) {
86
+ return /^[A-Z_][A-Z0-9_]*$/.test(varName);
87
+ }
88
+
89
+ /**
90
+ * Get supported file extensions
91
+ * @returns {string[]}
92
+ */
93
+ export function getSupportedExtensions() {
94
+ return SUPPORTED_EXTENSIONS;
95
+ }
96
+
97
+ /**
98
+ * Get regex patterns used for scanning
99
+ * @returns {RegExp[]}
100
+ */
101
+ export function getPatterns() {
102
+ return PATTERNS;
103
+ }