承接 jessegall/code-commandments 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

jessegall/code-commandments

Composer 安装命令:

composer require jessegall/code-commandments

包简介

A Laravel package for enforcing code commandments through prophets who judge and absolve transgressions

README 文档

README

This is a personal tool I built for my own projects. It's public in case others find it useful or want to fork it for their own coding standards.

A PHP package that enforces coding standards through automated validation, designed specifically for Claude Code (Anthropic's AI coding assistant). Works as a standalone CLI tool or as a Laravel package.

Why This Exists

When working with Claude Code, I needed a way to:

  1. Teach Claude my coding standards - So it writes code the way I want from the start
  2. Automatically check Claude's output - Catch violations immediately after Claude makes changes
  3. Provide actionable feedback - Give Claude clear instructions on what to fix

This package hooks into Claude Code's hook system to create a feedback loop:

┌─────────────────────────────────────────────────────────────────┐
│                     Claude Code Session                         │
├─────────────────────────────────────────────────────────────────┤
│  1. Session starts                                              │
│     └─> Hook runs: commandments:scripture                       │
│         └─> Claude learns all coding rules                      │
│                                                                 │
│  2. Claude writes/modifies code                                 │
│                                                                 │
│  3. After changes complete                                      │
│     └─> Hook runs: commandments:judge --git                     │
│         └─> Claude sees any violations                          │
│         └─> Claude fixes them automatically                     │
│                                                                 │
│  4. Repeat until code is "righteous" (no violations)            │
└─────────────────────────────────────────────────────────────────┘

All output is plain text optimized for AI assistants - concise, actionable, no decorative ASCII art.

Installation

composer require --dev jessegall/code-commandments

Laravel

Publish the configuration file:

php artisan vendor:publish --tag=commandments-config

Standalone (non-Laravel)

Run the init command to set up everything at once (config file, Claude Code hooks, CLAUDE.md):

vendor/bin/commandments init

Then edit the generated commandments.php to define your scrolls using __DIR__-based paths:

return [
    'scrolls' => [
        'backend' => [
            'path' => __DIR__ . '/src',
            'extensions' => ['php'],
            'prophets' => [
                \JesseGall\CodeCommandments\Prophets\Backend\NoRawRequestProphet::class,
            ],
        ],
    ],
];

Auto-detect mode

Use --auto-detect to automatically scan your project structure and generate a working config:

vendor/bin/commandments init --auto-detect

This scans the current directory and its immediate subdirectories, detects project types (PHP and/or frontend), and generates commandments.php with appropriate scrolls, paths, and all available prophets pre-configured.

Detection rules:

  • PHP: directory has composer.json and an app/ or src/ folder containing .php files
  • Frontend: directory has package.json and contains .vue, .ts, or .tsx files

For monorepos with multiple subprojects, each detected project gets its own scrolls (e.g. api-backend, dashboard-frontend).

Run commands via the commandments binary:

vendor/bin/commandments judge
vendor/bin/commandments repent
vendor/bin/commandments scripture

Sacred Terminology

Technical Term Biblical Term
Violation Sin / Transgression
Fix/Auto-fix Repent / Absolution
Warning Prophecy
Validator Prophet
Validator class [Name]Prophet
Validators folder Prophets/
Pass Righteous / Blessed
Fail Sinful / Fallen
Review Confession
Mark as reviewed Absolve
Groups Scrolls

Commands

Every command is available via both Laravel artisan (php artisan commandments:<cmd>) and the standalone CLI (vendor/bin/commandments <cmd>). The standalone CLI also accepts --config=<path> to point at a custom config file.

Command Purpose
abandon Leave the current pilgrimage early (judge/repent return; any gate your profile enforces still applies)
absolve Absolve a single finding (warning OR sin) by fingerprint/location, with a required reason
autofix Auto-fix the CURRENT pilgrimage prophet ([AUTO-FIXABLE] findings only), in place
feature-request Propose a NEW rule / enhancement as a GitHub issue (no finding needed; allowed mid-pilgrimage)
init Initialize code commandments for a standalone project
install-skills Install the Code Commandments skills into .claude/skills/
install-sync-hook Install a git post-merge hook that auto-runs sync --after=previous when composer.lock changes
judge Judge the codebase for sins against the commandments
migrate-config Convert a legacy array-style prophets list to the fluent ProphetClass::make()->… form
next Advance the pilgrimage to the next finding (forward-only)
pilgrimage Begin the forward-only doctrine walk (resets state; next advances it)
profile Show, list, or switch the active code-commandments profile (disabled/grind/phased/sins-only)
repent Auto-fix findings that can be automatically resolved — sins and [AUTO-FIXABLE] warnings (no severity bump needed)
report Report a prophet false-positive / wrong rule as a GitHub issue (to PROPOSE a new rule, use commandments feature-request)
reports Show the status of prophet reports this project filed (resolved upstream yet?)
scaffold Generate recommended support classes (Option, FromArrayOnly, …) into your namespace
scripture List all commandments and their descriptions
skills List the available Code Commandments skills (what they teach + where to read)
sync Add newly available prophets to your config file
todo List the still-unresolved file:line locations for the current pilgrimage prophet (compact; does not advance)
update Stay current: wire the composer lifecycle scripts, then sync prophets / scaffold / skills / hooks

abandon

Leave the current pilgrimage early (judge/repent return; any gate your profile enforces still applies).

absolve

Absolve a single finding (warning OR sin) by fingerprint/location, with a required reason.

Flag Argument Description
--config, -c <value> Path to config file
--fingerprint <value> The finding fingerprint shown by judge --next
--at <value> Target a finding by location instead of a fingerprint — path:line (or path:from-to), exactly as judge prints it; combine with --prophet to disambiguate ties
--reason <value> Why the rule does not apply / is consciously accepted here (required; sins included)
--all Baseline the queue: absolve every current advisory finding at once (sins still block)
--warnings Batch-absolve every WARNING in scope under one --reason; hard-refuses if any sin is in scope (absolves nothing)
--scope <value> Limit --warnings to changed files: "git" (vs tracked state) or "staged" (the index)
--prophet <value> Limit --warnings to one prophet (partial name match), e.g. --prophet=DuplicateCode — one scan, not one-per-finding
--clear Remove every ordinary absolution (post-commit reset so nothing stays hidden); report-linked absolutions persist until their issue is answered

autofix

Auto-fix the CURRENT pilgrimage prophet ([AUTO-FIXABLE] findings only), in place.

Flag Argument Description
--config, -c <value> Path to config file
--scroll <value> Scroll to walk
--dry-run Show what would be fixed without making changes

feature-request

Propose a NEW rule / enhancement as a GitHub issue (no finding needed; allowed mid-pilgrimage).

Flag Argument Description
--config, -c <value> Path to config file
--stdin Read the proposal body from STDIN (robust for multi-paragraph text — no shell-quoting)
--reason-file <value> Read the proposal body from a file (alternative to the positional text / --stdin)
--title <value> Short issue title; defaults to a summary of the proposal
--proposed-prophet <value> Proposed name for the new prophet you are suggesting
--rubric <value> Proposed APPLY/LEAVE rubric for the suggested rule
--repo <value> GitHub repo (owner/name) to file the issue on

init

Initialize code commandments for a standalone project.

Flag Argument Description
--force Overwrite existing files
--auto-detect Auto-detect projects and generate config

install-skills

Install the Code Commandments skills into .claude/skills/.

Flag Argument Description
--config, -c <value> Path to config file
--force Overwrite existing skill files
--auto Refresh only when skills.auto_refresh is enabled (session-start hook); otherwise do nothing

install-sync-hook

Install a git post-merge hook that auto-runs sync --after=previous when composer.lock changes.

Flag Argument Description
--force Overwrite an existing post-merge hook

judge

Judge the codebase for sins against the commandments.

Flag Argument Description
--config, -c <value> Path to config file
--scroll <value> Filter by specific scroll (group)
--prophet <value> Summon a specific prophet by name
--file <value> Judge a specific file
--files <value> Judge specific files (comma-separated)
--path <value> Override the scroll path and target a specific directory (bypasses all excludes — use to scan subtrees regardless of config)
--git Only judge files that are new or changed in git
--staged Only judge files staged for commit (what the pre-commit gate uses)
--branch Judge everything changed since the branch base, INCLUDING committed work (survives intermediate commits — the grind reckoning)
--no-profile Ignore the active profile for this run: scan the WHOLE scroll and show warnings, regardless of the profile (audit the full codebase)
--absolve Mark files as absolved after confession
--no-cache Force a fresh judge — never read the findings cache (the pre-commit gate uses this to stay authoritative)
--no-parallel Judge sequentially (no forked workers) — use on a platform without pcntl or to debug
--next Show exactly one finding at a time (fix or absolve to advance)
--plan Print the remediation roadmap: every finding ordered root-cause-first as a numbered checklist (the penance plan)
--gate-probe INTERNAL: run a fresh scan only for its exit code (used by the pre-push / Stop gates). Bypasses the pilgrimage lock but suppresses the findings report, so it is no use for browsing

migrate-config

Convert a legacy array-style prophets list to the fluent ProphetClass::make()->… form.

Flag Argument Description
--config, -c <value> Path to commandments.php config file
--write Rewrite the config file IN PLACE (a .bak backup is kept); otherwise only print + write a reference file
--out <value> Where to write the reference file (default: alongside the config)

next

Advance the pilgrimage to the next finding (forward-only).

Flag Argument Description
--config, -c <value> Path to commandments.php config file
--scroll <value> Scroll to walk

pilgrimage

Begin the forward-only doctrine walk (resets state; next advances it).

Flag Argument Description
--config, -c <value> Path to commandments.php config file
--scroll <value> Scroll to walk
--is-complete INTERNAL: exit 0 only if THIS session has genuinely walked the whole pilgrimage (the pre-push gate uses this to grant a completed walk one push). Recomputed from the cursor — a hand-written complete flag does not pass
--clear INTERNAL: discard the pilgrimage state (the pre-push gate consumes a completed walk so the next push re-arms the gate)

profile

Show, list, or switch the active code-commandments profile (disabled/grind/phased/sins-only).

Flag Argument Description
--config, -c <value> Path to config file
--brief Print the active profile briefing (session-start hook)
--drift-check Re-brief only when the profile changed (per-turn hook)

repent

Auto-fix findings that can be automatically resolved — sins and [AUTO-FIXABLE] warnings (no severity bump needed).

Flag Argument Description
--config, -c <value> Path to config file
--scroll <value> Filter by specific scroll (group)
--prophet <value> Use a specific prophet for repentance
--file <value> Repent sins in a specific file
--files <value> Repent sins in specific files (comma-separated)
--git Force working-tree scope. Bare repent otherwise adopts the active profile scope (like judge)
--input <value> Input for a parameterized fixer, repeatable: --input key=value
--dry-run Show what would be fixed without making changes

report

Report a prophet false-positive / wrong rule as a GitHub issue (to PROPOSE a new rule, use commandments feature-request).

Flag Argument Description
--config, -c <value> Path to config file
--prophet <value> The prophet that misbehaved (name or class)
--reason <value> What is wrong (false positive / wrong rule / unclear) — or, with --feature-request, what to build and why
--file <value> File where it was flagged
--line <value> Line number
--fingerprint <value> The finding fingerprint from judge --next — records a report-linked absolution so the finding stays quiet until the issue is answered
--at <value> Target the finding by location instead of a fingerprint — path:line (or path:from-to), exactly as judge prints it; records the report-linked absolution and infers --prophet/--file/--line. Combine with --prophet to disambiguate ties
--feature-request DEPRECATED — moved to commandments feature-request "&lt;text&gt;". Still works for one release, then removed
--title <value> (deprecated feature-request) Short issue title; defaults to a summary of --reason
--proposed-prophet <value> (deprecated feature-request) Proposed name for a new prophet you are suggesting
--rubric <value> (deprecated feature-request) Proposed APPLY/LEAVE rubric for the suggested rule
--repo <value> GitHub repo (owner/name) to file the issue on

reports

Show the status of prophet reports this project filed (resolved upstream yet?).

Flag Argument Description
--check Quiet hook mode: print only newly-resolved reports

scaffold

Generate recommended support classes (Option, FromArrayOnly, …) into your namespace.

Flag Argument Description
--config, -c <value> Path to config file
--force Overwrite existing support classes
--auto Refresh only when scaffold.auto_refresh is enabled (session-start hook); otherwise do nothing

scripture

List all commandments and their descriptions.

Flag Argument Description
--config, -c <value> Path to config file
--scroll <value> Filter by specific scroll (group)
--prophet <value> Show details for a specific prophet
--detailed Show full descriptions with examples

skills

List the available Code Commandments skills (what they teach + where to read).

sync

Add newly available prophets to your config file.

Flag Argument Description
--config, -c <value> Path to commandments.php config file
--after <value> Override the floor: only add prophets introduced after this version (e.g. 1.4.0), or previous for the last synced version.
--all OPT OUT of removal-respecting sync: add EVERY available prophet missing from the config (initial setup / deliberate full re-sync). Without this, sync NEVER re-adds a prophet you removed.
--dry-run Show what would be added without modifying the file

todo

List the still-unresolved file:line locations for the current pilgrimage prophet (compact; does not advance).

Flag Argument Description
--config, -c <value> Path to commandments.php config file
--scroll <value> Scroll to walk

update

Stay current: wire the composer lifecycle scripts, then sync prophets / scaffold / skills / hooks.

Flag Argument Description
--config, -c <value> Path to commandments.php config file

Summon a New Prophet (Laravel only)

# Create a new backend prophet
php artisan make:prophet NoMagicNumbers --scroll=backend

# Create a new frontend prophet
php artisan make:prophet NoInlineStyles --scroll=frontend --type=frontend

# Create a prophet that can auto-fix
php artisan make:prophet NoUnusedImports --repentable

# Create a prophet that requires manual review
php artisan make:prophet ComplexLogicReview --confession

Claude Code Integration

Automated Hooks

Claude Code supports hooks - shell commands that run at specific points during a session. This package leverages hooks to create an automated feedback loop.

Laravel projects:

php artisan commandments:install-hooks

Standalone projects (included in init, or run separately):

vendor/bin/commandments init

Both commands write the hook wiring + briefing to .claude/settings.local.json — the gitignored, per-developer local settings file, never the committed settings.json — so your checked-in settings stay ours-free. (A legacy consumer whose hooks were committed in settings.json is migrated automatically on the next sync/profile write.) The standalone version uses vendor/bin/commandments instead of php artisan.

Example hooks configuration (in .claude/settings.local.json):

{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "vendor/bin/commandments scripture 2>/dev/null || true"
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "vendor/bin/commandments judge --git 2>/dev/null; exit 0"
          }
        ]
      }
    ]
  }
}

How it works:

Hook When it runs What it does
SessionStart When Claude Code session begins Shows all commandments so Claude knows the rules
Stop After Claude finishes a response Runs judge --git to check changed files

The --git flag ensures only new/modified files are checked, keeping feedback focused and fast.

Typical workflow:

  1. You ask Claude to implement a feature
  2. Claude writes the code
  3. Hook automatically runs commandments:judge --git
  4. If violations found, Claude sees them and fixes automatically
  5. Repeat until code passes all checks

Configuration

Configure your scrolls in config/commandments.php:

return [
    'scrolls' => [
        'backend' => [
            'path' => app_path(),
            'extensions' => ['php'],
            'exclude' => ['Console/Kernel.php'],
            'prophets' => [
                // Simple registration (no config needed)
                Backend\NoRawRequestProphet::class,
                Backend\NoJsonResponseProphet::class,

                // With per-prophet configuration
                Backend\ControllerPrivateMethodsProphet::class => [
                    'max_private_methods' => 3,
                    'min_method_lines' => 3,
                ],
            ],
        ],
        'frontend' => [
            'path' => resource_path('js'),
            'extensions' => ['vue', 'ts', 'js'],
            'prophets' => [
                Frontend\NoFetchAxiosProphet::class,
                Frontend\CompositionApiProphet::class,

                // Configure max lines thresholds
                Frontend\LongVueFilesProphet::class => [
                    'max_vue_lines' => 200,
                ],
                Frontend\LongTsFilesProphet::class => [
                    'max_ts_lines' => 200,
                ],

                // Configure allowed Tailwind patterns for style overrides
                Frontend\StyleOverridesProphet::class => [
                    'allowed_patterns' => [
                        // Width/height
                        '/^(min-|max-)?(w|h)-/',
                        '/^size-/',

                        // Flexbox
                        '/^flex$/',
                        '/^inline-flex$/',
                        '/^items-/',
                        '/^justify-/',

                        // Transitions & animations
                        '/^transition/',
                        '/^duration-/',
                        '/^animate-/',

                        // Interactions
                        '/^cursor-/',
                        '/^opacity-/',
                    ],
                ],
            ],
        ],
    ],

    'confession' => [
        'tablet_path' => storage_path('commandments/confessions.json'),
    ],
];

Per-Prophet Configuration

Prophets can be registered in two ways:

  1. Simple registration - Just the class name when no config is needed:

    Backend\NoRawRequestProphet::class,
  2. With configuration - Class name as key, config array as value:

    Backend\ControllerPrivateMethodsProphet::class => [
        'max_private_methods' => 3,
    ],

Per-Prophet Exclusions

You can exclude specific paths for individual prophets. This is useful when a rule shouldn't apply to certain files:

'prophets' => [
    // Exclude legacy controllers from this rule
    Backend\ConstructorDependencyInjectionProphet::class => [
        'exclude' => ['Http/Controllers/Legacy', 'Http/Controllers/Api/V1'],
    ],

    // Combine exclusions with other config options
    Backend\ControllerPrivateMethodsProphet::class => [
        'max_private_methods' => 3,
        'exclude' => ['Http/Controllers/ReportController.php'],
    ],
],

The exclusion uses substring matching - if the path contains any of the excluded strings, that prophet will skip the file.

Configurable Prophets

Prophet Config Key Default Description
LongVueFilesProphet max_vue_lines 200 Maximum lines in Vue files
LongTsFilesProphet max_ts_lines 200 Maximum lines in script sections
ControllerPrivateMethodsProphet max_private_methods 3 Max private methods in controllers
ControllerPrivateMethodsProphet min_method_lines 3 Min lines for method to count
StyleOverridesProphet allowed_patterns [] Additional Tailwind patterns to allow

StyleOverridesProphet Patterns

The StyleOverridesProphet flags appearance classes on base components (Button, Card, etc.) but allows layout classes by default. You can extend the allowed patterns:

Frontend\StyleOverridesProphet::class => [
    'allowed_patterns' => [
        // These are in ADDITION to built-in layout patterns
        '/^(min-|max-)?(w|h)-/',  // Width/height
        '/^flex$/',               // Flex display
        '/^items-/',              // Flex alignment
        '/^cursor-/',             // Cursor styles
        '/^transition/',          // Transitions
    ],
],

Built-in allowed patterns (always allowed):

  • Margin/padding: m-, p-, space-, gap-
  • Grid layout: col-span-, row-span-, etc.
  • Flex behavior: flex-1, grow, shrink, self-
  • Positioning: absolute, relative, top-, z-
  • Display: hidden, block, inline-block

Built-in Prophets

Backend (PHP)

107 prophets.

Prophet Auto-fix What it enforces
AnchorEnumComparisonProphet Yes Anchor a CompareSelf set comparison on the non-null enum instance instead of the static form
BehaviouralEnumDispatchProphet Extract a wide behavioural per-enum-case dispatch into strategy objects + a registration map
ComputedPropertyMustHookProphet Computed properties must use property hooks instead of constructor assignment
ConfigKeyContractProphet A config() read must target a declared config key — a missing path is a silent null
ConstantsAndPropertiesFirstProphet Yes Declare all constants and properties at the top of the class, before any methods
ConstructorDependencyInjectionProphet Move service dependencies from controller methods to constructor
ControllerPrivateMethodsProphet Extract private methods to service classes when controller exceeds limit
DataClassFromArrayOnlyProphet Yes Every Data class must use the FromArrayOnly trait
DataClumpToValueObjectProphet 3+ values that always travel together across calls should be a value object
DeadProducerProphet A private method that returns a value nobody uses should be void (or its callers should use the result)
DemeterEndpointReachProphet Ask the owner with its intent method instead of reaching through $x->endpoint->field to branch (Law of Demeter)
DuplicateCodeProphet Extract duplicated code fragments instead of copy-pasting a method body
EagerRegistryProphet A registry is eagerly hydrated + read-only — lookups must not lazily build or populate-on-miss
EncapsulateModelMutationProphet Flag direct model attribute writes followed by save() — encapsulate the change as a named behaviour method on the model
EnumCaseMustBeDocumentedProphet Every enum case must have a descriptive doc comment above it explaining what the case is for
ExplicitDataFactoryProphet Yes Keep Data construction explicit — from() takes an array; map objects in named forX() factories
FeatureEnvyProphet Move a query over another object's internals onto that object (tell-don't-ask)
FormRequestTypedGettersProphet Add explicit return types to FormRequest getter methods
HardcodedLiteralShouldBeConfigProphet A literal hardcoded into a consumer that reads it from config elsewhere should read from config too
KebabCaseRoutesProphet Route URIs must use kebab-case
LongDocblockProphet Keep docblocks to one short narrative sentence above the @-tag block
LongMethodProphet Keep methods short and focused on a single responsibility
MigrationModelDriftProphet A typed migration column (json/bool/datetime/decimal) must have a matching model cast
MixedConfigValueUsedTypedProphet An env()-backed config value strict-compared to a number is always false — cast it first
NoArrayBagProphet Do not pass array<string, mixed> bags around — give the bag a Fluent value class
NoArrayStringIndexingProphet Prefer typed DTOs over string-indexed arrays for structured data
NoAuthUserInDataClassesProphet Use #[FromAuthenticatedUser] attribute instead of auth()->user() in Data classes
NoCoalesceOnNonNullableProphet Do not ??-coalesce a value that is never null — the default is dead
NoCompactProphet Do not bridge variables and arrays by name with compact()/extract()
NoConditionalArraySpreadProphet Assemble conditional array shapes with a builder, not a spread of a ternary with an empty arm
NoContainerResolutionProphet Prefer constructor injection over container resolution (app(), resolve(), App::make())
NoDirectRequestInputProphet Use typed FormRequest getters instead of direct request data access
NoExternalDataFromProphet Yes Keep Spatie ::from() inside the Data class — no custom from* factories, no external ::from()
NoFacadesInServicesProphet Do not call Laravel facades in services — inject the underlying contract via the constructor
NoInlineBootLogicProphet Model boot hooks should only dispatch events, not contain business logic
NoInlineParamDocProphet Yes Declare a parameter type with @param on the function docblock, not an inline /** @var */
NoInlineValidationProphet Move validation to FormRequest instead of inline $request->validate()
NoJsonResponseProphet Use Inertia responses instead of JSON in web controllers
NoManualHydrationProphet Do not hand-roll array-to-object hydration — extend Spatie Data and use ::from()
NoNullCoalesceToNullProphet Yes Drop the no-op ?? null — it returns the left side unchanged
NoOptionInUnionProphet Do not union Option with other types or null — Option is the whole type
NoOptionToNullProphet Yes Do not unwrap an Option back to null with unwrapOr(null)
NoRawLiteralProphet Yes Do not write raw magic literals (empties, newlines, …) — name them with T_String / T_Json / T_Array / T_Int
NoRawRequestProphet Use FormRequest classes instead of raw Request in controllers
NoRedundantDefaultArgumentProphet Yes Do not pass an argument equal to the parameter default — the default is already applied
NoRepeatedHydrationProphet Do not re-hydrate the same field with ::from() — declare it as the type so it hydrates once
NoRequestDataPassthroughProphet Inject request in Data class instead of passing computed values to from()
NoSwallowedNotFoundProphet Do not catch a not-found exception just to swallow it into null/false/[] — let it throw
NoValidatedMethodProphet Use typed getters instead of $request->validated()
OneRulePerFilterProphet A filter()/reject() closure should hold ONE rule — split an && chain, and say !(…) as reject(…)
OptionDisciplineProphet Model absence exactly when it is real — adopt Option for value-or-nothing, never for always-value
OutOfPurposeProphet A class with a role marker (*Registry/*Data/*Resolver) whose body shows a structural second-engine signal (reflection in a registry, an assembler cluster in a DTO, a store in a resolver) is doing a second job — extract it
PassThroughDependencyProphet A dependency only forwarded to one collaborator, never used itself, should be injected there
PreferClassifierCompositionProphet Compose classifier checks with anyOf()/allOf(), not a ||/&& chain of ->matches()
PreferCoalesceFactoryProphet Hoist new ValueObject($nullableOrLoose) ceremony into a total ::coalesce() factory
PreferCoalesceForProphet Yes Use T_Array::coalesceFor($array, $key) instead of double-coalescing a dynamic dictionary lookup
PreferCoalescingFactoryProphet Build a wrapper via a total/coalescing factory, not cond ? new T(...) : null + null-guards
PreferCoercionHelperProphet Yes Extract a repeated inline cast-with-fallback (is_x($v) ? (cast) $v : default) into a named coercion helper
PreferCollectionPipelineProphet Prefer a Collection chain over nested array_* compositions (they read inside-out)
PreferConfigDrivenRegistryProphet An enum whose cases mirror a config-registered set should be driven by a config registry
PreferDataCollectionOfProphet Do not hand-roll a Data collection with ::from() in a loop — use #[DataCollectionOf] / ::collect()
PreferDataTransformersProphet Serialize Data objects through ->toArray()/transformers, not a hand-rolled mapping
PreferDefaultFallbackProphet Move a call-site presence-check-then-fallback into the callee as a default parameter
PreferDefaultOverNullableProphet Prefer a $default parameter over a nullable/Option when every caller substitutes a fixed fallback
PreferEmptyOverNullProphet Return an empty collection/bag instead of null — an empty instance is the absence
PreferEnumCaseGroupsProphet Name reused subsets of an enum on the enum — do not re-inline the same case-group
PreferEnumForClosedSetFieldProphet Yes Suggest an enum for a string field whose name denotes a closed set
PreferFirstClassCallableProphet A forwarding closure should be a first-class callable — fn ($x) => f($x) is f(...)
PreferInjectionOverSingletonProphet Prefer dependency injection over a hand-rolled singleton
PreferInterfaceOverTypeListProphet Classify via a marker interface or the AST, not a hardcoded list of type names
PreferNamedBranchFactoryProphet Extract a non-trivial ->then() branch factory into a named *Factory method returning callable
PreferNamedExceptionsProphet Do not pass message strings at throw sites — throw named exceptions via static factories
PreferNativeEnumProphet Prefer a native enum over a hand-rolled constant class
PreferNativeTypedAccessorProphet Yes Use the receiver's native typed accessor instead of coercing its untyped get()
PreferNullCoalescingProphet Use ?? (or Option::unwrapOr) instead of a self-fallback ternary
PreferNullObjectDefaultsProphet Yes Prefer Null Object defaults over nullable params normalized in the body
PreferSprintfProphet Yes Prefer sprintf() over string interpolation — separate the template from its values
PreferStaticOverInvokableConstructProphet Prefer a static factory over (new X(...))(...) for project-owned classes
PreferTotalOverNullableProphet Make a method total or throw when every caller already de-nulls its nullable return
PreferTypeCoalesceProphet Yes Prefer T_*::coalesce() over ?? &lt;empty literal&gt; on a nullable typed value
PreferTypeMethodOverInlineDispatchProphet Move per-case dispatch and type-constant mappings onto the type, not inline at the call site
PreferTypedBoundaryProphet Type values at the deserialization boundary instead of leaking mixed for consumers to re-coerce.
PreferYieldOverAccumulatorProphet Prefer returning / yielding typed results over threading a write-only accumulator parameter through a class
PushGenericToSourceProphet Push a type to its source @return instead of re-asserting it with a call-site @var
QueryModelsThroughQueryMethodProphet Yes Query models through the ::query() method instead of direct static calls
ReadonlyDataPropertiesProphet Remove readonly from Data properties with value-injecting attributes like #[WithCast]
RegistryBaseBypassProphet A Registry subclass that overrides all() to a private store leaves inherited register() dead
RegistryNamingHonestyProphet A class shaped like a registry (register + keyed store + lookup) should be named *Registry and extend a base
RegistryPatternProphet When several classes hand-roll the registry shape, extract a shared base (scaffold one)
RegistryPurityProphet A registry stays a pure keyed store of its target type — resolution/query methods belong on a collaborator
RegistryReturnContractProphet A registry returns the item or throws — not Option<T> or T | null (with a has() companion)
RepeatedFallbackProphet Do not copy-paste a fallback chain — hoist a repeated ?? / ?: into a named static factory
ResolverNamingHonestyProphet A *Resolver should do first-match dispatch (ideally via the kernel) — otherwise rename off the suffix
ResolverPatternProphet Drive first-match dispatch and predicate code into the resolver + Predicate pattern
SecretToLogOrResponseProphet SECURITY: a secret (config token/password, ->password) must not be logged or dumped unredacted
SetNamingHonestyProphet A class shaped like a set (add + iterate, no keyed lookup) should be named *Set and extend a base
SetReturnContractProphet A set is a total, iterate-only collection — has(): bool, no Option/nullable leak, and no keyed get(string) lookup (that is a registry)
ShortClosureProphet Keep anonymous functions short — extract a big closure to a named private method
StringMatchMirrorsEnumProphet A match/switch over strings that mirror an enum's cases should dispatch on the enum
StringsThatShouldBeEnumsProphet Use enum cases instead of raw string literals for closed-set values
SuggestCompareSelfTraitProphet Yes Use a CompareSelf-style trait helper instead of chained enum equality comparisons
TaintedInputToSinkProphet SECURITY: request input must not reach raw SQL / exec / unserialize without sanitization
ThrowOnUnhandledCaseProphet Throw a named exception for an unhandled closed-set case — do not model an invariant violation as null/Option
TooManyParametersProphet Keep parameter lists short — group related parameters into an object
TranslationKeyCongruenceProphet A __()/trans() key must exist in a lang file — a missing key renders as the key string
TypeHonestyProphet Type honesty at the boundary — no empty-string fake for a required slot; no all-nullable boundary DTO
WideUnionTypeProphet Yes Avoid wide type unions — model value-or-nothing as an Option

Frontend (Vue / TypeScript)

29 prophets.

Prophet Auto-fix What it enforces
ArrowFunctionAssignmentsProphet Prefer named function declarations over arrow function assignments
CompositionApiProphet Use <script setup> Composition API instead of Options API
ConditionalArrayBuildingProphet Consider disabled flags pattern instead of conditional array building
ContentLikePropsProphet Consider using slots instead of content-like props
DeepNestingProphet Avoid deeply nested templates - consider extracting components
EmitsTypeScriptProphet Use TypeScript interface for defineEmits instead of runtime declaration
ExplicitDefaultSlotProphet Use explicit <template #default> when using named slots
InlineDialogProphet Extract inline dialog definitions to separate components
InlineEmitTransformProphet Avoid inline emit handlers with transformation logic in templates
InlineMarkupProphet Avoid excessive native HTML markup - extract components instead
InlineTypeCastingProphet Avoid inline type casting in template bindings
KebabCasePropsProphet Yes Props should be bound using kebab-case in templates
LongTsFilesProphet TypeScript files in components should be under 200 lines
LongVueFilesProphet Keep Vue files under 200 lines by extracting components
LoopsWithIndexedStateProphet Extract loop items with indexed state to separate components
MultipleSlotDefinitionsProphet Components with slots must use defineSlots for type safety
NoFetchAxiosProphet Use Inertia requests instead of fetch/axios
PageDataAccessProphet Page components should use PageData indexed access for prop types
PropsTypeScriptProphet Use TypeScript interface for defineProps instead of runtime declaration
RepeatingPatternsProphet Detect repeating patterns that could be extracted into reusable components or composables
RouterHardcodedUrlsProphet Never hardcode URLs in router calls
ScriptFirstProphet Thou shalt put script before template
StyleOverridesProphet Avoid style/class overrides on base components - use semantic props instead
SwitchCaseProphet Use SwitchCase component instead of v-if chains comparing the same variable
SwitchCheckboxVModelProphet Use v-model for Switch/Checkbox components, not v-model:checked or :checked
TemplateVForProphet Yes Use <template v-for> wrapper instead of v-for on elements
TemplateVIfProphet Yes Thou shalt wrap v-if/v-else in template elements
WatchIfPatternProphet Use whenever() instead of watch() with if condition
WayfinderRoutesProphet Never hardcode URLs in href attributes

Creating Custom Prophets

Basic PHP Prophet

<?php

namespace App\Prophets\Backend;

use JesseGall\CodeCommandments\Commandments\PhpCommandment;
use JesseGall\CodeCommandments\Results\Judgment;

class NoMagicNumbersProphet extends PhpCommandment
{
    public function description(): string
    {
        return 'Thou shalt not use magic numbers';
    }

    public function detailedDescription(): string
    {
        return 'Magic numbers should be extracted to named constants...';
    }

    public function judge(string $filePath, string $content): Judgment
    {
        $ast = $this->parse($content);

        if ($ast === null) {
            return $this->skip('Unable to parse PHP file');
        }

        // Your judgment logic here...

        return $this->righteous();
    }
}

Using the Pipeline API

The package provides fluent pipeline APIs for both PHP and Vue file analysis.

PHP Pipeline (PhpPipeline)

use JesseGall\CodeCommandments\Support\Pipes\Php\PhpPipeline;

public function judge(string $filePath, string $content): Judgment
{
    return PhpPipeline::make($filePath, $content)
        ->onlyControllers()  // Filter to Laravel controllers only
        ->pipe(ExtractMethods::class)
        ->pipe(FilterPrivateMethod::class)
        ->mapToSins(fn ($ctx) => /* create sins */)
        ->judge();
}

Available helper methods:

Method Description
onlyControllers() Filter to Laravel controller classes
onlyDataClasses() Filter to Laravel Data classes
onlyFormRequestClasses() Filter to FormRequest classes
returnRighteousIfNoClass() Return righteous if no class found
returnRighteousWhenClassHasAttribute($attr) Skip if class has specific attribute

Vue Pipeline (VuePipeline)

use JesseGall\CodeCommandments\Support\Pipes\Vue\VuePipeline;

public function judge(string $filePath, string $content): Judgment
{
    return VuePipeline::make($filePath, $content)
        ->inTemplate()  // Extract template, return righteous if not found
        ->matchAll('/pattern/')
        ->sinsFromMatches('Message', 'Suggestion')
        ->judge();
}

Available helper methods:

Method Description
inTemplate() Extract template section, return righteous if not found
inScript() Extract script section, return righteous if not found
onlyPageFiles() Filter to files in Pages/ directory
onlyComponentFiles() Filter to files in Components/ directory
excludePartialFiles() Exclude files in Partials/ directory
matchAll($pattern) Find all regex matches in current section
sinsFromMatches($msg, $suggestion) Convert matches to sins
mapToSins($callback) Custom sin mapping
mapToWarnings($callback) Custom warning mapping

Accessing Configuration

Prophets can access their configuration via $this->config():

class MyProphet extends PhpCommandment
{
    public function judge(string $filePath, string $content): Judgment
    {
        $maxLines = (int) $this->config('max_lines', 100);
        $patterns = $this->config('allowed_patterns', []);

        // Use config values...
    }
}

Then configure in config/commandments.php:

'prophets' => [
    MyProphet::class => [
        'max_lines' => 150,
        'allowed_patterns' => ['/^custom-/'],
    ],
],

Vue/TypeScript Auto-fixing

For Vue and TypeScript auto-fixing, install the Node.js dependencies:

cd vendor/jessegall/code-commandments/node
npm install

Testing

./vendor/bin/phpunit

License

MIT License

统计信息

  • 总下载量: 1.18k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 14
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-01-20

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固