class Detector::Php::Cli

Overview

Detects PHP command-line applications. SOURCE-anchored only (never composer.json, where symfony/console is a transitive web dependency): a Symfony Console command class / use, Laravel Zero, League CLImate, Minicli, Laravel Artisan ($signature), Robo (Robo\Tasks), WP-CLI (WP_CLI::add_command / WP_CLI_Command), or builtin getopt / $argv indexing.

Defined in:

detector/detectors/php/cli.cr

Constant Summary

ARGV_INDEX = /\$argv\s*\[/
ARTISAN_SIGNATURE = /protected\s+(?:static\s+)?\$signature\s*=\s*['"]/
AS_COMMAND = /#\[\s*AsCommand\b/
CLIMATE = /\buse\s+League\\CLImate\\CLImate\b/
GETOPT = /\bgetopt\s*\(/
LARAVEL_ZERO = /\buse\s+LaravelZero\\Framework\b/
MINICLI = /\buse\s+Minicli\\(?:App|Command)\b/
ROBO_MARKER = /Robo\\Tasks\b/
SF_COMMAND = /\bclass\s+\w+\s+extends\s+(?:\\?Symfony\\Component\\Console\\Command\\)?Command\b/
USE_SF_CONSOLE = /\buse\s+Symfony\\Component\\Console\b/
WP_ADD_COMMAND = /WP_CLI::add_command\s*\(/
WP_COMMAND_CLASS = /extends\s+WP_CLI_Command\b/

Instance Method Summary

Instance methods inherited from class Detector

applicable?(filename : String) : Bool applicable?, detect(filename : String, file_contents : String) : Bool detect, gemfile_dependency?(file_contents : String, gem_name : String) : Bool gemfile_dependency?, gemspec_dependency?(file_contents : String, gem_name : String) : Bool gemspec_dependency?, idempotent? : Bool idempotent?, logger : NoirLogger logger, name : String name, path_sensitive? : Bool path_sensitive?

Constructor methods inherited from class Detector

new(options : Hash(String, YAML::Any)) new

Instance Method Detail

def applicable?(filename : String) : Bool #
Description copied from class Detector

Cheap filename-only filter the detector pass uses to skip #detect on files the detector cannot possibly match. The default true preserves prior behavior (every detector runs on every file). Override with the same predicate the body of #detect starts with — e.g., filename.ends_with?(".py") for a Python framework detector — so the detector loop avoids the #detect dispatch on files outside the detector's language.

On large codebases (saleor's 4255 .py files) this lifts ~100 virtual #detect calls per file out of the hot loop because most detectors' inner first-line is exactly this kind of cheap filename check.


[View source]
def detect(filename : String, file_contents : String) : Bool #

NOTE deliberately kept as a sequential || chain. A single Regex.union of these 12 patterns benchmarked 1.38× SLOWER on non-matching PHP content — each pattern's distinctive literal keeps PCRE2's fast scan, which the wide alternation defeats.


[View source]
def set_name #

[View source]