<?xml version="1.0"?>
<ruleset
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="vendor/squizlabs/php_codesniffer/phpcs.xsd"
    name="Psalm coding standard"
>
    <description>The coding standard for Psalm.</description>

    <!-- **************************************************************************************************************
      *  Configuration                                                                                                *
      ************************************************************************************************************** -->

    <config name="php_version" value="70400"/>
    <config name="installed_paths" value="../../slevomat/coding-standard"/>

    <arg name="basepath" value="."/>

    <!-- **************************************************************************************************************
      *  Files to include/exclude                                                                                     *
      ************************************************************************************************************** -->

    <file>examples/</file>
    <file>src/</file>
    <file>tests/</file>

    <!-- These are just examples and stub classes/files, so it doesn't really matter if they're PSR-2 compliant. -->
    <exclude-pattern>src/Psalm/Internal/Stubs/</exclude-pattern>
    <exclude-pattern>tests/fixtures/</exclude-pattern>


    <!-- **************************************************************************************************************
      *  STANDARD:  Generic                                                                                           *
      ************************************************************************************************************** -->

    <!--
        Restrict line length.
        https://github.com/squizlabs/PHP_CodeSniffer/blob/master/src/Standards/Generic/Docs/Files/LineLengthStandard.xml
     -->
    <rule ref="Generic.Files.LineLength">
        <exclude-pattern>tests</exclude-pattern>
        <exclude-pattern>src/Psalm/Internal/Type/TemplateStandinTypeReplacer.php</exclude-pattern>
    </rule>


    <!-- **************************************************************************************************************
      *  STANDARD:  PSR1                                                                                              *
      ************************************************************************************************************** -->

    <rule ref="PSR1.Files.SideEffects.FoundWithSymbols">
        <exclude-pattern>bin/update-property-map.php</exclude-pattern>
    </rule>

    <!-- **************************************************************************************************************
      *  STANDARD:  PSR2                                                                                              *
      ************************************************************************************************************** -->

    <rule ref="PSR2"/>

    <!--
        Namespace Declarations.
        https://github.com/squizlabs/PHP_CodeSniffer/blob/master/src/Standards/PSR2/Docs/Namespaces/UseDeclarationStandard.xml
     -->
    <rule ref="PSR2.Namespaces.UseDeclaration">
        <exclude-pattern>*</exclude-pattern>
    </rule>


    <!-- **************************************************************************************************************
      *  STANDARD:  Squiz                                                                                             *
      ************************************************************************************************************** -->

    <!--
        The self keyword should be used instead of the current class name.
        https://github.com/squizlabs/PHP_CodeSniffer/blob/master/src/Standards/Squiz/Docs/Classes/SelfMemberReferenceStandard.xml
     -->
    <rule ref="Squiz.Classes.SelfMemberReference"/>


    <!-- **************************************************************************************************************
      *  STANDARD:  SlevomatCodingStandard                                                                            *
      ************************************************************************************************************** -->

    <!--
        Handles enforcement and line spacing of declare(strict_types=1).
        https://github.com/slevomat/coding-standard#slevomatcodingstandardtypehintsdeclarestricttypes-
     -->
    <rule ref="SlevomatCodingStandard.TypeHints.DeclareStrictTypes">
        <properties>
            <property name="declareOnFirstLine" value="false"/>
            <property name="linesCountBeforeDeclare" value="1"/>
            <property name="linesCountAfterDeclare" value="1"/>
            <property name="spacesCountAroundEqualsSign" value="0"/>
        </properties>

        <exclude name="SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing"/>
    </rule>

    <!--
        Requires only one namespace in a file.
        https://github.com/slevomat/coding-standard#slevomatcodingstandardnamespacesrequireonenamespaceinfile
     -->
    <rule ref="SlevomatCodingStandard.Namespaces.RequireOneNamespaceInFile"/>

    <!--
        Enforces formatting of namespace.
        https://github.com/slevomat/coding-standard#slevomatcodingstandardnamespacesnamespacedeclaration-
     -->
    <rule ref="SlevomatCodingStandard.Namespaces.NamespaceDeclaration"/>

    <!--
        Enforces number of lines before and after namespace.
        https://github.com/slevomat/coding-standard#slevomatcodingstandardnamespacesnamespacespacing-
     -->
    <rule ref="SlevomatCodingStandard.Namespaces.NamespaceSpacing">
        <properties>
            <property name="linesCountBeforeNamespace" value="1"/>
            <property name="linesCountAfterNamespace" value="1"/>
        </properties>
    </rule>

    <rule ref="Squiz.Classes.ValidClassName">
        <exclude-pattern>src/Psalm/Storage/Assertion/Empty_.php</exclude-pattern>
    </rule>

    <!--
        Handle imports from namespaces.
        https://github.com/slevomat/coding-standard#slevomatcodingstandardnamespacesreferenceusednamesonly-
     -->
    <rule ref="SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly">
        <properties>
            <property name="allowFullyQualifiedExceptions" value="false"/>
            <property name="allowFullyQualifiedGlobalFunctions" value="false"/>
            <property name="allowFullyQualifiedGlobalConstants" value="false"/>
            <property name="allowFullyQualifiedGlobalClasses" value="false"/>

            <property name="allowFullyQualifiedNameForCollidingClasses" value="false"/>
            <property name="allowFullyQualifiedNameForCollidingFunctions" value="false"/>
            <property name="allowFullyQualifiedNameForCollidingConstants" value="false"/>

            <property name="allowFallbackGlobalFunctions" value="false"/>
            <property name="allowFallbackGlobalConstants" value="false"/>

            <property name="allowPartialUses" value="true"/>

            <property name="searchAnnotations" value="true"/>
        </properties>
    </rule>

    <!--
        Looks for unused imports from other namespaces.
        https://github.com/slevomat/coding-standard#slevomatcodingstandardnamespacesunuseduses-
     -->
    <rule ref="SlevomatCodingStandard.Namespaces.UnusedUses">
        <properties>
            <property name="searchAnnotations" value="true"/>
        </properties>
    </rule>

    <!--
        Checks whether uses at the top of a file are alphabetically sorted.
        https://github.com/slevomat/coding-standard#slevomatcodingstandardnamespacesalphabeticallysorteduses-
     -->
    <rule ref="SlevomatCodingStandard.Namespaces.AlphabeticallySortedUses">
        <properties>
            <property name="psr12Compatible" value="true"/>
            <property name="caseSensitive" value="true"/>
        </properties>
    </rule>

    <!--
        Enforces configurable number of lines before/after/between use.
        https://github.com/slevomat/coding-standard#slevomatcodingstandardnamespacesusespacing-
     -->
    <rule ref="SlevomatCodingStandard.Namespaces.UseSpacing">
        <properties>
            <property name="linesCountBetweenUseTypes" value="1"/>
        </properties>
    </rule>

    <!--
        Checks for missing return typehints and useless @return annotations.
        https://github.com/slevomat/coding-standard#slevomatcodingstandardtypehintsreturntypehint-
     -->
    <rule ref="SlevomatCodingStandard.TypeHints.ReturnTypeHint">
        <exclude name="SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingTraversableTypeHintSpecification"/>
    </rule>

    <!--
        Enforces consistent formatting of return typehints.
        https://github.com/slevomat/coding-standard#slevomatcodingstandardtypehintsreturntypehintspacing-
     -->
    <rule ref="SlevomatCodingStandard.TypeHints.ReturnTypeHintSpacing">
        <properties>
            <property name="spacesCountBeforeColon" value="0"/>
        </properties>
    </rule>

    <!--
        Requires using a underscore separator for long numbers.
        https://github.com/slevomat/coding-standard/#slevomatcodingstandardnumbersrequirenumericliteralseparator
    -->
    <rule ref="SlevomatCodingStandard.Numbers.RequireNumericLiteralSeparator">
        <properties>
            <property name="enable" value="true"/>
            <property name="minDigitsBeforeDecimalPoint" value="5"/>
        </properties>
    </rule>

    <!--
        Requires use of null coalesce operator when possible.
        https://github.com/slevomat/coding-standard/#slevomatcodingstandardcontrolstructuresrequirenullcoalesceoperator-
    -->
    <rule ref="SlevomatCodingStandard.ControlStructures.RequireNullCoalesceOperator" />

    <!--
        Requires use of null coalesce equal operator when possible.
        https://github.com/slevomat/coding-standard/#slevomatcodingstandardcontrolstructuresrequirenullcoalesceequaloperator-
    -->
    <rule ref="SlevomatCodingStandard.ControlStructures.RequireNullCoalesceEqualOperator">
        <properties>
            <property name="enable" value="true"/>
        </properties>
    </rule>

    <!--
        Enforces using short form of list syntax, [...] instead of list(...).
        https://github.com/slevomat/coding-standard/#slevomatcodingstandardphpshortlist-
    -->
    <rule ref="SlevomatCodingStandard.PHP.ShortList"/>

    <!-- https://github.com/slevomat/coding-standard/blob/master/doc/functions.md#slevomatcodingstandardfunctionsrequirearrowfunction- -->
    <rule ref="SlevomatCodingStandard.Functions.RequireArrowFunction"/>

    <!--
        Forces uniform arrow function style
        https://github.com/slevomat/coding-standard/blob/master/doc/functions.md#slevomatcodingstandardfunctionsarrowfunctiondeclaration-
    -->
    <rule ref="SlevomatCodingStandard.Functions.ArrowFunctionDeclaration">
        <properties>
            <property name="spacesCountAfterKeyword" value="0"/>
            <property name="spacesCountBeforeArrow" value="1"/>
            <property name="spacesCountAfterArrow" value="1"/>
            <property name="allowMultiLine" value="true"/>
        </properties>
    </rule>

    <rule ref="SlevomatCodingStandard.Commenting.EmptyComment"/>
    <rule ref="SlevomatCodingStandard.Commenting.DocCommentSpacing"/>
    <rule ref="SlevomatCodingStandard.TypeHints.ParameterTypeHint">
        <exclude name="SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingTraversableTypeHintSpecification"/>
    </rule>
    <rule ref="SlevomatCodingStandard.TypeHints.PropertyTypeHint">
        <exclude name="SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingTraversableTypeHintSpecification"/>
        <!-- TODO: Remove in Psalm 6 -->
        <include-pattern>bin/*</include-pattern>
        <include-pattern>src/Psalm/Internal/*</include-pattern>
        <include-pattern>tests/*</include-pattern>
    </rule>
    <rule ref="SlevomatCodingStandard.Arrays.TrailingArrayComma"/>
    <rule ref="SlevomatCodingStandard.Functions.RequireTrailingCommaInCall"/>
    <rule ref="SlevomatCodingStandard.Functions.RequireTrailingCommaInClosureUse"/>
    <rule ref="SlevomatCodingStandard.Functions.RequireTrailingCommaInDeclaration"/>
</ruleset>
