Git Product home page Git Product logo

tlint's Introduction

TLint Logo


Latest Version on Packagist

Install (Requires PHP 8.1+)

Note TLint is intended to work with the tools included in Duster. To receive the best coverage we recommend using Duster to install and configure TLint.

# Include in project
composer require tightenco/tlint --dev

# Include globally
composer global require tightenco/tlint

Upgrade

# Upgrade in project
composer update tightenco/tlint

#Upgrade globally
composer global update tightenco/tlint

Upgrading from 8.x to 9.x

TLint 9 requires PHP >= 8.1.

tformat.json has been dropped in favor of a single tlint.json file.

Now linting the following files and directories:

  • public/
  • bootstrap/
  • server.php
  • app/Http/Middleware/RedirectIfAuthenticated.php
  • Exceptions/Handler.php
  • app/Http/Controllers/Auth/
  • app/Http/Kernel.php

To continue excluding these files and directories add them to your tlint.json file under excluded.

Upgrading from 7.x to 8.x

A significant number of formatters were added between the 7.x and 8.x releases. If you want to roll these out gradually or disable them altogether, you can use the disabled setting in your tlint.json config.

Upgrading from 6.x to 7.x

TLint focuses on linting and formatting issues other tools are not able to catch. The 7.x release removes lints and formatters covered by tools in Duster. If you need to add these back you can grab them from an earlier version of TLint and follow the Custom Configuration documentation.

What Is It?

This is an opinionated code linter (with growing support for auto-formatting!) for Tighten flavored code conventions for Laravel and PHP.

For example, Laravel has many available ways to pass variables from a controller to a view:

A)

$value = 'Hello, World!';

return view('view', compact('value'));

B)

return view('view', ['value' => 'Hello, World!']);

C)

return view('view')
    ->with('value', 'Hello, World!');

In this case TLint will warn if you are not using the B) method. This example is a sort of "meta layer" of code linting, allowing teams to avoid higher level sticking points of code review / discussions.

Usage

For entire project (you must pass the lint command to use other options)

tlint

For individual files and specific directories

tlint lint index.php
tlint lint app

You can also lint only diff files by running the following with unstaged git changes

tlint lint --diff
tlint lint src --diff

Want the output from a file as JSON? (Primarily used for integration with editor plugins)

tlint lint test.php --json

Want the output from a file as a checkstyle XML report? (Primarily used with CI tools like reviewdog and cs2pr)

tlint lint test.php --checkstyle

Want to only run a single linter?

tlint lint --only=ArrayParametersOverViewWith

Example Output

Linting TestLaravelApp/routes/web.php
============
Lints:
============
! Prefer `view(...)->with(...)` over `view(..., [...])`.
5 : `    return view('test', ['test' => 'test']);``

Formatting

Using the same conventions as above, but using the format command, you can auto-fix some lints:

tlint format

Linting Configuration

TLint Ships with 2 "preset" styles: Laravel & Tighten. The Laravel preset is intended to match the conventions agreed upon by the Laravel framework contributors, while the Tighten preset is intended to match those agreed upon by Tighten team members.

The default configuration is "tighten" flavored, but you may change this by adding a tlint.json file to your project's root directory with the following schema:

You may further customize the linters used by adding specific lint names to the "disabled" list. You may disable linting for specific directories by adding them to the "excluded" list. You may provide custom paths by adding them to the "paths" lists.

{
    "preset": "laravel",
    "disabled": ["ArrayParametersOverViewWith"],
    "excluded": ["tests/"],
    "paths": [
        {
            "controllers": ["app/Domain/Http/Controllers"]
        }
    ]
}

Custom Configuration & Presets

You can also add your own custom preset and linters by providing a fully-qualified class name as the preset. For example, if you created a custom preset class:

namespace App\Support\Linting;

use Tighten\TLint\Presets\PresetInterface;

class Preset implements PresetInterface
{
  public function getLinters() : array
  {
    return [
      CustomLinter::class,
    ];
  }

  public function getFormatters() : array
  {
    return [
        CustomFormatter::class,
    ];
  }
}

Then your config could look like:

{
    "preset": "App\\Support\\Linting\\Preset"
}

This lets you define custom linting/formatting functionality, or modify the existing linters/formatters to your liking.

Editor Integrations

Available Linters

Linter Description
ApplyMiddlewareInRoutes Apply middleware in routes (not controllers).
ArrayParametersOverViewWith Prefer view(..., [...]) over view(...)->with(...).
FullyQualifiedFacades Import facades using their full namespace.
MailableMethodsInBuild Mailable values (from and subject etc) should be set in build().
NoDatesPropertyOnModels The $dates property was deprecated in Laravel 8. Use $casts instead.
NoDocBlocksForMigrationUpDown Remove doc blocks from the up and down method in migrations.
NoJsonDirective Use blade {{ $model }} auto escaping for models, and double quotes via json_encode over @json blade directive: <vue-comp :values='@json($var)'> -> <vue-comp :values="{{ $model }}"> OR <vue-comp :values="{!! json_encode($var) !!}">
NoLeadingSlashesOnRoutePaths No leading slashes on route paths.
NoRequestAll No request()->all(). Use request()->only(...) to retrieve specific input values.
NoSpaceAfterBladeDirectives No space between blade template directive names and the opening paren:@section ( -> @section(
OneLineBetweenClassVisibilityChanges Class members of differing visibility must be separated by a blank line
PureRestControllers You should not mix restful and non-restful public methods in a controller
QualifiedNamesOnlyForClassName Fully Qualified Class Names should only be used for accessing class names
RemoveLeadingSlashNamespaces Prefer Namespace\... over \Namespace\....
RequestHelperFunctionWherePossible Use the request(...) helper function directly to access request values wherever possible
RequestValidation Use request()->validate(...) helper function or extract a FormRequest instead of using $this->validate(...) in controllers
SpaceAfterBladeDirectives Put a space between blade control structure names and the opening paren:@if( -> @if (
SpacesAroundBladeRenderContent Spaces around blade rendered content:{{1 + 1}} -> {{ 1 + 1 }}
UseAnonymousMigrations Prefer anonymous class migrations.

General PHP

  • OneLineBetweenClassVisibilityChanges
  • QualifiedNamesOnlyForClassName
  • RemoveLeadingSlashNamespaces

Laravel

  • ApplyMiddlewareInRoutes
  • ArrayParametersOverViewWith
  • FullyQualifiedFacades
  • MailableMethodsInBuild
  • NoLeadingSlashesOnRoutePaths
  • NoDocBlocksForMigrationUpDown
  • NoJsonDirective
  • NoSpaceAfterBladeDirectives, SpaceAfterBladeDirectives
  • PureRestControllers
  • RequestHelperFunctionWherePossible
  • RequestValidation
  • SpacesAroundBladeRenderContent
  • UseAnonymousMigrations

Available Formatters

Notes about formatting

  • Formatting is designed to alter the least amount of code possible.
  • Import related formatters are not designed to alter grouped imports.
Formatter Description
ArrayParametersOverViewWith Prefer view(..., [...]) over view(...)->with(...).
FullyQualifiedFacades Import facades using their full namespace.
MailableMethodsInBuild Mailable values (from and subject etc) should be set in build().
NoDatesPropertyOnModels Use $casts instead of $dates on Eloquent models.
NoDocBlocksForMigrationUpDown Removes doc blocks from the up and down method in migrations.
NoLeadingSlashesOnRoutePaths No leading slashes on route paths.
NoSpaceAfterBladeDirectives No space between blade template directive names and the opening paren:@section ( -> @section(
OneLineBetweenClassVisibilityChanges Class members of differing visibility must be separated by a blank line
RemoveLeadingSlashNamespaces Prefer Namespace\... over \Namespace\....
RequestHelperFunctionWherePossible Use the request(...) helper function directly to access request values wherever possible
RequestValidation Use request()->validate(...) helper function or extract a FormRequest instead of using $this->validate(...) in controllers
SpaceAfterBladeDirectives Put a space between blade control structure names and the opening paren:@if( -> @if (
SpacesAroundBladeRenderContent Spaces around blade rendered content:{{1 + 1}} -> {{ 1 + 1 }}
UseAnonymousMigrations Prefer anonymous class migrations.

General PHP

  • OneLineBetweenClassVisibilityChanges
  • RemoveLeadingSlashNamespaces

Laravel

  • ArrayParametersOverViewWith
  • FullyQualifiedFacades
  • MailableMethodsInBuild
  • NoDatesPropertyOnModels
  • NoDocBlocksForMigrationUpDown
  • NoLeadingSlashesOnRoutePaths
  • NoSpaceAfterBladeDirectives
  • RequestHelperFunctionWherePossible
  • RequestValidation
  • SpaceAfterBladeDirectives
  • SpacesAroundBladeRenderContent
  • UseAnonymousMigrations

Contributing

Please see CONTRIBUTING for details.

Security

If you discover any security related issues, please email [email protected] instead of using the issue tracker.

Credits

License

The MIT License (MIT). Please see License File for more information.

tlint's People

Contributors

andrewmile avatar bakerkretzmar avatar benbjurstrom avatar benholmen avatar d9705996 avatar darkboywonder avatar delta1186 avatar driftingly avatar erictendian avatar faxblaster avatar gummibeer avatar igorgaming avatar inxilpro avatar jakebathman avatar jcorrego avatar johnbacon avatar josecanhelp avatar loganhenson avatar mattstauffer avatar mazedlx avatar nickknissen avatar peter279k avatar sbine avatar szepeviktor avatar tonysm avatar wulfheart avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tlint's Issues

False Positive `PureRestControllers`

You should not mix restful and non-restful methods in a controller
<?php

namespace App\Http\Controllers;

use App\Data\Models\Profession;

class ProfessionController extends Controller
{
    public function show($slug)
    {
        return view('professions.show')
            ->with('profession', Profession::where('slug', $slug)->firstOrFail())
            ->with('professions', Profession::all());
    }
}

Undefined method from NoParensEmptyInstantiations lint

Using PHP 7.1.11

If you need any other info, let me know. This is a great package, will look to send you some PRs soon!

PHP Fatal error:  Uncaught Error: Call to undefined method PhpParser\Node\Expr\Variable::toString() in /Users/macbook/.composer/vendor/loganhenson/tlint/src/Linters/NoParensEmptyInstantiations.php:24
Stack trace:
#0 /Users/macbook/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/FindingVisitor.php(41): Tighten\Linters\NoParensEmptyInstantiations->Tighten\Linters\{closure}(Object(PhpParser\Node\Expr\New_))
#1 /Users/macbook/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(115): PhpParser\NodeVisitor\FindingVisitor->enterNode(Object(PhpParser\Node\Expr\New_))
#2 /Users/macbook/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(197): PhpParser\NodeTraverser->traverseNode(Object(PhpParser\Node\Stmt\Return_))
#3 /Users/macbook/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(108): PhpParser\NodeTraverser->traverseArray(Array)
#4 /Users/macbook/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(197): PhpParser\NodeTraverser->traverseNode(Object(PhpParser\Node in /Users/macbook/.composer/vendor/loganhenson/tlint/src/Linters/NoParensEmptyInstantiations.php on line 24

Fatal error: Uncaught Error: Call to undefined method PhpParser\Node\Expr\Variable::toString() in /Users/macbook/.composer/vendor/loganhenson/tlint/src/Linters/NoParensEmptyInstantiations.php on line 24

Error: Call to undefined method PhpParser\Node\Expr\Variable::toString() in /Users/macbook/.composer/vendor/loganhenson/tlint/src/Linters/NoParensEmptyInstantiations.php on line 24

Call Stack:
    0.0003     357824   1. {main}() /Users/macbook/.composer/vendor/loganhenson/tlint/bin/tlint:0
    0.0315    1606216   2. Symfony\Component\Console\Application->run() /Users/macbook/.composer/vendor/loganhenson/tlint/bin/tlint:34
    0.0511    1855152   3. Symfony\Component\Console\Application->doRun() /Users/macbook/.composer/vendor/symfony/console/Application.php:148
    0.0515    1857944   4. Symfony\Component\Console\Application->doRunCommand() /Users/macbook/.composer/vendor/symfony/console/Application.php:240
    0.0515    1857944   5. Tighten\Commands\LintCommand->run() /Users/macbook/.composer/vendor/symfony/console/Application.php:938
    0.0517    1859352   6. Tighten\Commands\LintCommand->execute() /Users/macbook/.composer/vendor/symfony/console/Command/Command.php:252
   12.7301    9493792   7. Tighten\Commands\LintCommand->lintFile() /Users/macbook/.composer/vendor/loganhenson/tlint/src/Commands/LintCommand.php:203
   12.7699   10092120   8. Tighten\TLint->lint() /Users/macbook/.composer/vendor/loganhenson/tlint/src/Commands/LintCommand.php:89
   12.7699   10092816   9. Tighten\Linters\NoParensEmptyInstantiations->lint() /Users/macbook/.composer/vendor/loganhenson/tlint/src/TLint.php:27
   12.7730   10085784  10. PhpParser\NodeTraverser->traverse() /Users/macbook/.composer/vendor/loganhenson/tlint/src/Linters/NoParensEmptyInstantiations.php:30
   12.7730   10085784  11. PhpParser\NodeTraverser->traverseArray() /Users/macbook/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:85
   12.7730   10086208  12. PhpParser\NodeTraverser->traverseNode() /Users/macbook/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:197
   12.7730   10086304  13. PhpParser\NodeTraverser->traverseArray() /Users/macbook/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:108
   12.7731   10087784  14. PhpParser\NodeTraverser->traverseNode() /Users/macbook/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:197
   12.7732   10087984  15. PhpParser\NodeTraverser->traverseArray() /Users/macbook/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:108
   12.7732   10088408  16. PhpParser\NodeTraverser->traverseNode() /Users/macbook/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:197
   12.7732   10088792  17. PhpParser\NodeTraverser->traverseArray() /Users/macbook/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:108
   12.7734   10090496  18. PhpParser\NodeTraverser->traverseNode() /Users/macbook/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:197
   12.7734   10090520  19. PhpParser\NodeVisitor\FindingVisitor->enterNode() /Users/macbook/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:115
   12.7734   10090520  20. Tighten\Linters\NoParensEmptyInstantiations->Tighten\Linters\{closure}() /Users/macbook/.composer/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/FindingVisitor.php:41

[bug] ClassThingsOrder.php line 79: Unknown statement

The linter throws the following exception when running:

PS D:\Users\projects\abc> tlint

In ClassThingsOrder.php line 79:

  Unknown statement


lint [--diff] [--json] [--] [<file or directory>]

PS D:\Users\Shantanu\projects\abc>

handle `use` aliasing

use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;

string interpolation

general default is (but this is not hard and fast rules)

  1. use concatenation when it’s not inline. “User: ” . $user->name()
  2. Use interpolation with braces when it’s simple and inline: “You’ve subscribe to the {$plan} plan.”
  3. Use sprintf for everything else.

Definite rule of “never use interpolation without braces”

The argument against interpolation without braces being that it’s just not very clear.

Ensure 1 line separation between visibility differing class members

Before

class Purchase extends Model
{
    public const CASH = 'cash';
    public const FINANCE = 'finance';
    public const LEASE = 'lease';
    protected $guarded = [
        'id',
    ];

After

class Purchase extends Model
{
    public const CASH = 'cash';
    public const FINANCE = 'finance';
    public const LEASE = 'lease';

    protected $guarded = [
        'id',
    ];

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.