(directory: RuleDirectoryInfo)
| 172 | } |
| 173 | |
| 174 | async function scanRuleDirectory(directory: RuleDirectoryInfo): Promise<RuleMetadata[]> { |
| 175 | try { |
| 176 | const stats = await fs.stat(directory.directoryPath) |
| 177 | if (!stats.isDirectory()) { |
| 178 | return [] |
| 179 | } |
| 180 | |
| 181 | const entries = await fs.readdir(directory.directoryPath, { withFileTypes: true, recursive: true }) |
| 182 | const fileInfo: RuleFileInfo[] = [] |
| 183 | |
| 184 | await Promise.all( |
| 185 | entries.map((entry) => |
| 186 | resolveRuleDirectoryEntry(entry, directory.directoryPath, fileInfo, 0, directory.directoryPath), |
| 187 | ), |
| 188 | ) |
| 189 | |
| 190 | return fileInfo |
| 191 | .filter(({ originalPath }) => shouldIncludeRuleFile(originalPath)) |
| 192 | .sort((a, b) => a.originalPath.toLowerCase().localeCompare(b.originalPath.toLowerCase())) |
| 193 | .map(({ originalPath, resolvedPath, isSymlink }) => { |
| 194 | const relativePath = path.relative(directory.directoryPath, originalPath) |
| 195 | const name = path.basename(originalPath) |
| 196 | return { |
| 197 | id: createRuleId(directory.scope, directory.kind, directory.modeSlug, relativePath), |
| 198 | name, |
| 199 | scope: directory.scope, |
| 200 | kind: directory.kind, |
| 201 | modeSlug: directory.modeSlug, |
| 202 | modeName: directory.modeName, |
| 203 | filePath: resolvedPath, |
| 204 | relativePath, |
| 205 | directoryPath: directory.directoryPath, |
| 206 | isSymlink, |
| 207 | } |
| 208 | }) |
| 209 | } catch (error) { |
| 210 | if (["ENOENT", "ENOTDIR"].includes((error as NodeJS.ErrnoException).code ?? "")) { |
| 211 | return [] |
| 212 | } |
| 213 | |
| 214 | throw error |
| 215 | } |
| 216 | } |
| 217 | |
| 218 | async function resolveRuleDirectoryEntry( |
| 219 | entry: Dirent, |
no test coverage detected