module CliEndpointSupport

Overview

Shared by the 21 src/analyzer/analyzers/{lang}/cli.cr analyzers, which all build the same thing: a set of cli://<binary> endpoints, one per (sub)command, so that flags and env vars discovered in different files merge onto one command.

It is a mixin rather than an inherited method because the CLI analyzers have no common base below Analyzer: 17 extend Analyzer directly, while the Go, JavaScript, Python and Ruby ones extend their language engine. Pushing this onto Analyzer itself would hand a cli://-specific constructor to all ~200 analyzers, so the mixin is included by exactly the 21 that want it.

The other helpers those files carry — cli_test_path?, <lang>_binary_name, cli_evidence? — each read a per-class constant whose value differs by language (Perl's test tree is /t/, Scala's is /it/, Groovy's is spec.groovy; the binary-name stem lists disagree too). Several are therefore textually identical while resolving to different regexes, so folding them on name would be a silent behaviour change. They stay where they are — but the fallback half of <lang>_binary_name, which is genuine duplication, lives here as cli_directory_binary_name.

Direct including types

Defined in:

analyzer/engines/cli_endpoint_support.cr

Constant Summary

CLI_LAYOUT_DIRS = Set {"src", "source", "sources", "bin", "cmd", "cmds", "command", "commands", "lib", "libs", "app", "apps", "main", "cli", "script", "scripts", "tool", "tools", "internal", "pkg", "exe", "console", "program", "programs", "code", "packages", "project", "projects", "test", "tests"}

Directory names that describe a project's layout rather than name the program inside it.

CLI_MANIFEST_BASENAMES = ["shard.yml", "go.mod", "Cargo.toml", "package.json", "deno.json", "deno.jsonc", "jsr.json", "pubspec.yaml", "mix.exs", "build.sbt", "build.sc", "pom.xml", "build.gradle", "build.gradle.kts", "settings.gradle", "settings.gradle.kts", "composer.json", "pyproject.toml", "setup.py", "setup.cfg", "Pipfile", "Gemfile", "stack.yaml", "package.yaml", "cabal.project", "deps.edn", "project.clj", "bb.edn", "Package.swift", "build.zig", "build.zig.zon", "cpanfile", "Makefile.PL", "dist.ini"] of ::String

Files that mark a project root. A CLI file's nearest enclosing manifest is the program it belongs to; two files under different manifests are two programs even when their inferred binary names collide.

Deliberately excludes CMakeLists.txt / meson.build: those are written per subdirectory in a normal build tree, so they mark layout rather than a project boundary and would split one program into many.

CLI_MANIFEST_EXTENSIONS = [".cabal", ".csproj", ".fsproj", ".vbproj", ".gemspec", ".rockspec", ".nimble"] of ::String

Manifests named after the project rather than by a fixed basename.

KEY_SEP = Char::ZERO

Separator inside the endpoint-map key. A NUL can appear in neither a path nor a URL, so the three parts of the key (configured base, project directory, URL) can never be confused for one another.