module FileHelper

Direct including types

Defined in:

models/file_helper.cr

Constant Summary

PUBLIC_FILE_IGNORE = Set {".gitkeep", ".keep", ".gitignore", ".DS_Store", ".placeholder"}

Version-control / OS placeholder files that sit inside public/ directories (often to keep an otherwise-empty dir in git) but are never served as real endpoints. Matched by exact basename so genuine static files keep flowing through — e.g. .well-known/dnt-policy.txt (basename dnt-policy.txt) is unaffected.

Instance Method Summary

Instance Method Detail

def all_files : Array(String) #

Get all files from CodeLocator


[View source]
def get_files_by_basename(basename : String) : Array(String) #

Files whose basename is exactly basename (uses cached index).


[View source]
def get_files_by_extension(extension : String) : Array(String) #

Get files filtered by extension (uses cached index for O(1) lookup)


[View source]
def get_files_by_extensions(extensions : Array(String)) : Array(String) #

Union of files matching any of extensions. Prefer this over parallel_analyze(all_files) + per-file extension filter: the monorepo file_map can be 10–100× larger than the language's source set, and walking it only to next on every non-matching path is pure overhead.


[View source]
def get_files_by_prefix(prefix : String) : Array(String) #

Get files filtered by path prefix

No File.directory? guard: the detector's walk only registers a path in file_map after next unless info.file? (see detect_techs), so every entry is already a regular file. The guard was a guaranteed-false stat(2) paid once per file per analyzer.


[View source]
def get_files_by_prefix_and_extension(prefix : String, extension : String) : Array(String) #

Get files filtered by both prefix and extension.

Narrows by extension first (O(1) index hit), then by root. The previous shape scanned the whole file_map and paid an under_normalized_root? test per file before looking at the extension at all — on a monorepo where the language's source set is a small slice of the tree that is mostly wasted work.


[View source]
def get_files_by_relative_path(relative_path : String, root : String = "") : Array(String) #

Scanned files whose path ends with relative_path (a a/b/c.py style module-ish suffix), optionally restricted to root.

The in-memory answer to Dir.glob("root/**/#{relative_path}"). The glob form walks every directory under the scan root — including the subtrees the detector pruned — so it costs a full filesystem traversal per call; this narrows by basename first and confirms the remaining path with ends_with?.

Scope note: this resolves against file_map, so it sees exactly the files noir actually scanned. A match the glob would have found under an ignored directory (node_modules/**/urls.py) or behind --exclude-path is deliberately not returned — resolving to a file the scan excluded would contradict every other analyzer lookup.


[View source]
def get_public_dir_files(base_path : String, folder : String) : Array(String) #

Helper to get public directories content from anywhere in the project


[View source]
def get_public_files(base_path : String, anchors : Array(String) = ["shard.yml", "Gemfile"]) : Array(String) #

Get public files (files that should be served as static content)

Returns files that are inside a public/ directory that is the sibling of a manifest file (shard.yml for Crystal, Gemfile for Ruby/Rails). The previous shape matched any */public/* substring under base_path, which had a real false-positive surface: a repo that hosts a Crystal framework fixture alongside an unrelated static site (e.g. a built docs directory at docs/public/) would have every file in the docs site surface as a framework endpoint. The previous fix scoped to shard.yml only, which broke Rails monorepos like App/Gemfile + App/public/secret.htmlApp/public/* no longer surfaced because there was no sibling shard.yml.


[View source]
def walked_path(expanded : String) : String #

The as-walked spelling of a path an analyzer resolved with File.expand_path — a config <include> target, a route file named from a source file. code_paths are reported the way the walker handed them over, so a resolved path has to be mapped back before it reaches a report: left absolute it puts the scanning machine's directory layout into anything shared, and a SARIF artifactLocation.uri that isn't repo-relative can't be matched to a file by GitHub code scanning.

Falls back to the input for a file outside the scan — there is nothing better to say about it.


[View source]