Skip to content

Commit 80b84f3

Browse files
authored
GH Actions/publish-wiki: auto-generate table of contents (#6)
This commit adds steps to the workflow to auto-generate a GitHub wiki compatible table of contents in most wiki pages. This reduces the risk of a TOC being out-of-date or containing incorrectly formatted links, as well as reduces the maintenance burden. This action uses the `doctoc` pages to generate the table of contents and this can be tested locally using the same steps as used in the GH Actions workflow: ``` npm install -g doctoc cp -v -a wiki _wiki doctoc ./_wiki/ --github --maxlevel 4 --update-only doctoc ./_wiki/Version-4.0-User-Upgrade-Guide.md --github --maxlevel 3 --update-only ``` Notes: * The files are copied to a `_wiki` directory - which is `.gitignore`d - before pre-processing to reduce the risk of the source files being accidentally updated (and committed), which would undo the automation. * The `--github` flag puts the TOC generation in GitHub compatible mode. * The `--update-only` flag means that only markdown files containing the `<!-- START doctoc -->` and `<!-- END doctoc -->` markers will be updated and files without those markers will be left alone. * By default, the TOC will contain all headers up to the indicated `--maxlevel`. For the V 4.0 Dev upgrade guide, this looked weird, what with some "Upgrading" headers being at level 4 and some at level 5. To mitigate this, a couple of headers have been turned into "bold phrases" instead. Along the same lines, for the V 4.0 User upgrade guide, the level 4 headers were always "Upgrading". Those belong with their parent heading and IMO do not need to be separately called out in the TOC, which explains the second call to `doctoc` to overrule the TOC for that file specifically with a `--maxlevel 3` setting. * The start/end markers have been added to all files which contained a TOC, except for one: `Reporting.md`. The reason for this exception is that the section order in the file does not match the current TOC order, with the existing TOC order making sense from a TOC point of view, while the section order makes sense from a "types of reports most used" point of view. Whether this page should be re-organized or not, is outside the scope of this PR. To allow contributors to review the resulting pre-processed wiki files, the files are uploaded as an artifact when a PR dry-run is being executed and a comment is posted on the PR requesting the contributor to review the pre-processed files. Includes adding a TOC to the Coding Standards Tutorial page and adding "back to top" links within the page. Ref: * https://github.com/thlorenz/doctoc
1 parent ad2ae7a commit 80b84f3

12 files changed

+108
-203
lines changed

.github/workflows/publish-wiki.yml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,31 @@ jobs:
3131
permissions:
3232
# Needed for the commit to the wiki.
3333
contents: write
34+
# Needed for the PR comment.
35+
pull-requests: write
3436

3537
steps:
3638
- name: Checkout code
3739
uses: actions/checkout@v4
3840

41+
42+
# ################################################################################
43+
# Update Wiki files.
44+
# ################################################################################
45+
46+
- name: Install DocToc table of contents generator
47+
run: npm install -g doctoc
48+
3949
- name: Copy wiki files to temporary location
4050
shell: bash
4151
run: cp -v -a wiki _wiki
4252

53+
- name: Update tables of contents
54+
run: doctoc ./_wiki/ --github --maxlevel 4 --update-only
55+
56+
- name: Re-run tables of contents with different settings for specific file
57+
run: doctoc ./_wiki/Version-4.0-User-Upgrade-Guide.md --github --maxlevel 3 --update-only
58+
4359
- name: Preface markdown files with warning not to edit in place
4460
shell: bash
4561
# yamllint disable rule:line-length
@@ -50,6 +66,43 @@ jobs:
5066
'1i\<!--\nWARNING: DO NOT EDIT THIS FILE IN THE WIKI.\nThis wiki is updated from the https://github.com/PHPCSStandards/PHP_CodeSniffer-documentation repository.\nSubmit a PR to that repository updating the relevant file in the /wiki/ subdirectory instead.\n-->\n' {} \;
5167
# yamllint enable rule:line-length
5268
69+
70+
# ################################################################################
71+
# Dry-run/PRs: upload artifact with pre-processed files and post comment in PR.
72+
# ################################################################################
73+
74+
# Retention is normally 90 days, but this artifact is only to help with reviewing PRs,
75+
# especially when new output blocks are added or the (workflow) code for existing ones
76+
# is updated. All in all, no need to keep the artifact for more than a few days.
77+
- name: "[PR only] Upload the preprocessed wiki files as an artifact"
78+
if: ${{ github.event_name == 'pull_request' }}
79+
id: artifact
80+
uses: actions/upload-artifact@v4
81+
with:
82+
name: wiki-files
83+
path: ./_wiki
84+
if-no-files-found: error
85+
retention-days: 10
86+
87+
- name: "[PR only] Post comment to review artifact"
88+
if: ${{ github.event_name == 'pull_request' }}
89+
uses: mshick/add-pr-comment@v2
90+
with:
91+
repo-token: ${{ secrets.GITHUB_TOKEN }}
92+
message: |
93+
Thank you for your PR.
94+
A dry-run has been executed on your PR, executing all markdown pre-processing for the wiki files.
95+
96+
Please review the resulting final markdown files via the [created artifact](${{ steps.artifact.outputs.artifact-url }}).
97+
This is especially important when adding new pages.
98+
99+
_N.B.: the above link will automatically be updated when this PR is updated._
100+
101+
102+
# ################################################################################
103+
# Deploy to the wiki in the PHPCS repo.
104+
# ################################################################################
105+
53106
- name: Check GitHub Git Operations status
54107
uses: crazy-max/ghaction-github-status@v4
55108
with:

wiki/About-Standards-for-PHP_CodeSniffer.md

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,7 @@
11
## Table of contents
22

3-
* [A Project ruleset or a standard ?](#a-project-ruleset-or-a-standard-)
4-
* [How does PHP_CodeSniffer determine which standard or ruleset to apply ?](#how-does-php_codesniffer-determine-which-standard-or-ruleset-to-apply-)
5-
* [About standards](#about-standards)
6-
* [Creating an external standard for PHP_CodeSniffer](#creating-an-external-standard-for-php_codesniffer)
7-
* [Creating new rules](#creating-new-rules)
8-
* [Naming conventions](#naming-conventions)
9-
* [1. Directory structure](#1-directory-structure)
10-
* [2. Sniff file name](#2-sniff-file-name)
11-
* [3. Namespace and class name](#3-namespace-and-class-name)
12-
* [Examples](#examples)
3+
<!-- START doctoc -->
4+
<!-- END doctoc -->
135

146
***
157

wiki/Advanced-Usage.md

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,7 @@
11
## Table of contents
22

3-
* [Specifying Valid File Extensions](#specifying-valid-file-extensions)
4-
* [Ignoring Files and Folders](#ignoring-files-and-folders)
5-
* [Ignoring Parts of a File](#ignoring-parts-of-a-file)
6-
* [Limiting Results to Specific Sniffs](#limiting-results-to-specific-sniffs)
7-
* [Filtering Errors and Warnings Based on Severity](#filtering-errors-and-warnings-based-on-severity)
8-
* [Replacing Tabs with Spaces](#replacing-tabs-with-spaces)
9-
* [Specifying an Encoding](#specifying-an-encoding)
10-
* [Using a Bootstrap File](#using-a-bootstrap-file)
11-
* [Using a Default Configuration File](#using-a-default-configuration-file)
12-
* [Specifying php.ini Settings](#specifying-phpini-settings)
13-
* [Setting Configuration Options](#setting-configuration-options)
14-
* [Deleting Configuration Options](#deleting-configuration-options)
15-
* [Viewing Configuration Options](#viewing-configuration-options)
16-
* [Printing Verbose Tokeniser Output](#printing-verbose-tokeniser-output)
17-
* [The Scope Map](#the-scope-map)
18-
* [The Level Map](#the-level-map)
19-
* [Printing Verbose Token Processing Output](#printing-verbose-token-processing-output)
20-
* [Quieting Output](#quieting-output)
21-
* [Understanding the Exit Codes](#understanding-the-exit-codes)
3+
<!-- START doctoc -->
4+
<!-- END doctoc -->
225

236
***
247

wiki/Coding-Standard-Tutorial.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@ In this tutorial, we will create a new coding standard with a single sniff. Our
22

33
Sniffs need to follow [strict directory layout and naming conventions](https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki/About-Standards-for-PHP_CodeSniffer#naming-conventions).
44

5+
## Table of contents
6+
7+
<!-- START doctoc -->
8+
<!-- END doctoc -->
9+
10+
***
11+
512
## Creating the Coding Standard Directory
613

714
All sniffs in PHP_CodeSniffer must belong to a coding standard. A coding standard is a directory with a specific sub-directory structure and a `ruleset.xml` file, so creating a standard is straight-forward.
@@ -39,6 +46,9 @@ The content of the `ruleset.xml` file should, at a minimum, be the following:
3946
> [!NOTE]
4047
> The ruleset.xml can be left quite small, as it is in this example coding standard. For information about the other features that the `ruleset.xml` provides, see the [[Annotated ruleset]].
4148
49+
<p align="right"><a href="#table-of-contents">back to top</a></p>
50+
51+
4252
## Creating the Sniff
4353

4454
A sniff requires a single PHP file that must be placed into a sub-directory to categorise the type of check it performs. Its name should clearly describe the standard that we are enforcing and must end with `Sniff.php`. For our sniff, we will name the PHP file `DisallowHashCommentsSniff.php` and place it into a `Commenting` sub-directory to categorise this sniff as relating to commenting. Run the following commands to create the category and the sniff:
@@ -54,24 +64,36 @@ $ touch Commenting/DisallowHashCommentsSniff.php
5464
5565
Each sniff must implement the `PHP_CodeSniffer\Sniffs\Sniff` interface so that PHP_CodeSniffer knows that it should instantiate the sniff once it's invoked. The interface defines two methods that must be implemented; `register` and `process`.
5666

67+
<p align="right"><a href="#table-of-contents">back to top</a></p>
68+
69+
5770
## The `register` and `process` Methods
5871

5972
The `register` method allows a sniff to subscribe to one or more token types that it wants to process. Once PHP_CodeSniffer encounters one of those tokens, it calls the `process` method with the `PHP_CodeSniffer\Files\File` object (a representation of the current file being checked) and the position in the stack where the token was found.
6073

6174
For our sniff, we are interested in single line comments. The `token_get_all` method that PHP_CodeSniffer uses to acquire the tokens within a file distinguishes doc comments and normal comments as two separate token types. Therefore, we don't have to worry about doc comments interfering with our test. The `register` method only needs to return one token type, `T_COMMENT`.
6275

76+
<p align="right"><a href="#table-of-contents">back to top</a></p>
77+
78+
6379
## The Token Stack
6480

6581
A sniff can gather more information about a token by acquiring the token stack with a call to the `getTokens` method on the `PHP_CodeSniffer\Files\File` object. This method returns an array and is indexed by the position where the token occurs in the token stack. Each element in the array represents a token. All tokens have a `code`, `type` and a `content` index in their array. The `code` value is a unique integer for the type of token. The `type` value is a string representation of the token (e.g., `'T_COMMENT'` for comment tokens). The `type` has a corresponding globally defined integer with the same name. Finally, the `content` value contains the content of the token as it appears in the code.
6682

6783
> [!NOTE]
6884
> Depending on the token, the token array may contain various additional indexes with further information on a token.
6985
86+
<p align="right"><a href="#table-of-contents">back to top</a></p>
87+
88+
7089
## Reporting Errors
7190

7291
Once an error is detected, a sniff should indicate that an error has occurred by calling the `addError` method on the `PHP_CodeSniffer\Files\File` object, passing in an appropriate error message as the first argument, the position in the stack where the error was detected as the second, a code to uniquely identify the error within this sniff and an array of data used inside the error message.
7392
Alternatively, if the violation is considered not as critical as an error, the `addWarning` method can be used.
7493

94+
<p align="right"><a href="#table-of-contents">back to top</a></p>
95+
96+
7597
## DisallowHashCommentsSniff.php
7698

7799
We now have to write the content of our sniff. The content of the `DisallowHashCommentsSniff.php` file should be the following:
@@ -135,6 +157,8 @@ public $supportedTokenizers = [
135157
];
136158
```
137159

160+
<p align="right"><a href="#table-of-contents">back to top</a></p>
161+
138162

139163
## Results
140164

@@ -173,3 +197,5 @@ FOUND 3 ERROR(S) AFFECTING 3 LINE(S)
173197
13 | ERROR | Hash comments are prohibited; found # Error.
174198
--------------------------------------------------------------------------------
175199
```
200+
201+
<p align="right"><a href="#table-of-contents">back to top</a></p>

wiki/Configuration-Options.md

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,7 @@
11
## Table of contents
22

3-
* [Setting the default coding standard](#setting-the-default-coding-standard)
4-
* [Setting the default report format](#setting-the-default-report-format)
5-
* [Hiding warnings by default](#hiding-warnings-by-default)
6-
* [Showing progress by default](#showing-progress-by-default)
7-
* [Using colors in output by default](#using-colors-in-output-by-default)
8-
* [Changing the default severity levels](#changing-the-default-severity-levels)
9-
* [Setting the default report width](#setting-the-default-report-width)
10-
* [Setting the default encoding](#setting-the-default-encoding)
11-
* [Setting the default tab width](#setting-the-default-tab-width)
12-
* [Setting the installed standard paths](#setting-the-installed-standard-paths)
13-
* [Setting the PHP version](#setting-the-php-version)
14-
* [Ignoring errors when generating the exit code](#ignoring-errors-when-generating-the-exit-code)
15-
* [Ignoring warnings when generating the exit code](#ignoring-warnings-when-generating-the-exit-code)
16-
* [Ignoring non-auto-fixable issues when generating the exit code (PHP_CodeSniffer >= 4.0.0)](#ignoring-non-auto-fixable-issues-when-generating-the-exit-code-php_codesniffer--400)
17-
* Setting tool paths
18-
* [CSSLint](#setting-the-path-to-csslint)
19-
* [Google Closure Linter](#setting-the-path-to-the-google-closure-linter)
20-
* [PHP](#setting-the-path-to-php)
21-
* [JSHint](#setting-the-path-to-jshint)
22-
* [JSLint](#setting-the-path-to-jslint)
23-
* [JavaScript Lint](#setting-the-path-to-javascript-lint)
24-
* [Zend Code Analyzer](#setting-the-path-to-the-zend-code-analyzer)
3+
<!-- START doctoc -->
4+
<!-- END doctoc -->
255

266
***
277

wiki/Customisable-Sniff-Properties.md

Lines changed: 2 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -4,70 +4,8 @@ For more information about changing sniff behaviour by customising your ruleset,
44

55
## Table of contents
66

7-
* [Generic Sniffs](#generic-sniffs)
8-
* [Generic.Arrays.ArrayIndent](#genericarraysarrayindent)
9-
* [Generic.CodeAnalysis.UnusedFunctionParameter](#genericcodeanalysisunusedfunctionparameter)
10-
* [Generic.ControlStructures.InlineControlStructure](#genericcontrolstructuresinlinecontrolstructure)
11-
* [Generic.Debug.ClosureLinter](#genericdebugclosurelinter)
12-
* [Generic.Debug.ESLint](#genericdebugeslint)
13-
* [Generic.Files.LineEndings](#genericfileslineendings)
14-
* [Generic.Files.LineLength](#genericfileslinelength)
15-
* [Generic.Formatting.MultipleStatementAlignment](#genericformattingmultiplestatementalignment)
16-
* [Generic.Formatting.SpaceAfterCast](#genericformattingspaceaftercast)
17-
* [Generic.Formatting.SpaceAfterNot](#genericformattingspaceafternot)
18-
* [Generic.Functions.OpeningFunctionBraceBsdAllman](#genericfunctionsopeningfunctionbracebsdallman)
19-
* [Generic.Functions.OpeningFunctionBraceKernighanRitchie](#genericfunctionsopeningfunctionbracekernighanritchie)
20-
* [Generic.Metrics.CyclomaticComplexity](#genericmetricscyclomaticcomplexity)
21-
* [Generic.Metrics.NestingLevel](#genericmetricsnestinglevel)
22-
* [Generic.NamingConventions.CamelCapsFunctionName](#genericnamingconventionscamelcapsfunctionname)
23-
* [Generic.PHP.ForbiddenFunctions](#genericphpforbiddenfunctions)
24-
* [Generic.PHP.NoSilencedErrors](#genericphpnosilencederrors)
25-
* [Generic.Strings.UnnecessaryStringConcat](#genericstringsunnecessarystringconcat)
26-
* [Generic.WhiteSpace.ArbitraryParenthesesSpacing](#genericwhitespacearbitraryparenthesesspacing)
27-
* [Generic.WhiteSpace.ScopeIndent](#genericwhitespacescopeindent)
28-
* [Generic.WhiteSpace.SpreadOperatorSpacingAfter](#genericwhitespacespreadoperatorspacingafter)
29-
* [PEAR Sniffs](#pear-sniffs)
30-
* [PEAR.Commenting.FunctionComment](#pearcommentingfunctioncomment)
31-
* [PEAR.ControlStructures.ControlSignature](#pearcontrolstructurescontrolsignature)
32-
* [PEAR.ControlStructures.MultiLineCondition](#pearcontrolstructuresmultilinecondition)
33-
* [PEAR.Formatting.MultiLineAssignment](#pearformattingmultilineassignment)
34-
* [PEAR.Functions.FunctionCallSignature](#pearfunctionsfunctioncallsignature)
35-
* [PEAR.Functions.FunctionDeclaration](#pearfunctionsfunctiondeclaration)
36-
* [PEAR.WhiteSpace.ObjectOperatorIndent](#pearwhitespaceobjectoperatorindent)
37-
* [PEAR.WhiteSpace.ScopeClosingBrace](#pearwhitespacescopeclosingbrace)
38-
* [PEAR.WhiteSpace.ScopeIndent](#pearwhitespacescopeindent)
39-
* [PSR2 Sniffs](#psr2-sniffs)
40-
* [PSR2.Classes.ClassDeclaration](#psr2classesclassdeclaration)
41-
* [PSR2.ControlStructures.ControlStructureSpacing](#psr2controlstructurescontrolstructurespacing)
42-
* [PSR2.ControlStructures.SwitchDeclaration](#psr2controlstructuresswitchdeclaration)
43-
* [PSR2.Methods.FunctionCallSignature](#psr2methodsfunctioncallsignature)
44-
* [PSR12 Sniffs](#psr12-sniffs)
45-
* [PSR12.Classes.AnonClassDeclaration](#psr12classesanonclassdeclaration)
46-
* [PSR12.ControlStructures.BooleanOperatorPlacement](#psr12controlstructuresbooleanoperatorplacement)
47-
* [PSR12.ControlStructures.ControlStructureSpacing](#psr12controlstructurescontrolstructurespacing)
48-
* [PSR12.Namespaces.CompoundNamespaceDepth](#psr12namespacescompoundnamespacedepth)
49-
* [PSR12.Operators.OperatorSpacing](#psr12operatorsoperatorspacing)
50-
* [Squiz Sniffs](#squiz-sniffs)
51-
* [Squiz.Classes.ClassDeclaration](#squizclassesclassdeclaration)
52-
* [Squiz.Commenting.FunctionComment](#squizcommentingfunctioncomment)
53-
* [Squiz.Commenting.LongConditionClosingComment](#squizcommentinglongconditionclosingcomment)
54-
* [Squiz.ControlStructures.ControlSignature](#squizcontrolstructurescontrolsignature)
55-
* [Squiz.ControlStructures.ForEachLoopDeclaration](#squizcontrolstructuresforeachloopdeclaration)
56-
* [Squiz.ControlStructures.ForLoopDeclaration](#squizcontrolstructuresforloopdeclaration)
57-
* [Squiz.ControlStructures.SwitchDeclaration](#squizcontrolstructuresswitchdeclaration)
58-
* [Squiz.CSS.ForbiddenStyles](#squizcssforbiddenstyles)
59-
* [Squiz.CSS.Indentation](#squizcssindentation)
60-
* [Squiz.Functions.FunctionDeclaration](#squizfunctionsfunctiondeclaration)
61-
* [Squiz.Functions.FunctionDeclarationArgumentSpacing](#squizfunctionsfunctiondeclarationargumentspacing)
62-
* [Squiz.PHP.CommentedOutCode](#squizphpcommentedoutcode)
63-
* [Squiz.PHP.DiscouragedFunctions](#squizphpdiscouragedfunctions)
64-
* [Squiz.PHP.ForbiddenFunctions](#squizphpforbiddenfunctions)
65-
* [Squiz.Strings.ConcatenationSpacing](#squizstringsconcatenationspacing)
66-
* [Squiz.WhiteSpace.FunctionSpacing](#squizwhitespacefunctionspacing)
67-
* [Squiz.WhiteSpace.MemberVarSpacing](#squizwhitespacemembervarspacing)
68-
* [Squiz.WhiteSpace.ObjectOperatorSpacing](#squizwhitespaceobjectoperatorspacing)
69-
* [Squiz.WhiteSpace.OperatorSpacing](#squizwhitespaceoperatorspacing)
70-
* [Squiz.WhiteSpace.SuperfluousWhitespace](#squizwhitespacesuperfluouswhitespace)
7+
<!-- START doctoc -->
8+
<!-- END doctoc -->
719

7210
***
7311

wiki/FAQ.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
## Table of contents
22

3-
* [Does PHP_CodeSniffer perform any code coverage or unit testing?](#does-php_codesniffer-perform-any-code-coverage-or-unit-testing)
4-
* [My code is fine! Why do I need PHP_CodeSniffer?](#my-code-is-fine-why-do-i-need-php_codesniffer)
5-
* [Does PHP_CodeSniffer parse my code to ensure it will execute?](#does-php_codesniffer-parse-my-code-to-ensure-it-will-execute)
6-
* [I don't agree with your coding standards! Can I make PHP_CodeSniffer enforce my own?](#i-dont-agree-with-your-coding-standards-can-i-make-php_codesniffer-enforce-my-own)
7-
* [How come PHP_CodeSniffer reported errors, I fixed them, now I get even more?](#how-come-php_codesniffer-reported-errors-i-fixed-them-now-i-get-even-more)
8-
* [What does PHP_CodeSniffer use to tokenize my code?](#what-does-php_codesniffer-use-to-tokenize-my-code)
3+
<!-- START doctoc -->
4+
<!-- END doctoc -->
95

106
***
117

wiki/Fixing-Errors-Automatically.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
## Table of contents
22

3-
* [About Automatic Fixing](#about-automatic-fixing)
4-
* [Using the PHP Code Beautifier and Fixer](#using-the-php-code-beautifier-and-fixer)
5-
* [Viewing Debug Information](#viewing-debug-information)
3+
<!-- START doctoc -->
4+
<!-- END doctoc -->
65

76
***
87

wiki/Usage.md

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
## Table of contents
22

3-
* [Getting Help from the Command Line](#getting-help-from-the-command-line)
4-
* [Checking Files and Folders](#checking-files-and-folders)
5-
* [Printing a Summary Report](#printing-a-summary-report)
6-
* [Printing Progress Information](#printing-progress-information)
7-
* [Specifying a Coding Standard](#specifying-a-coding-standard)
8-
* [Printing a List of Installed Coding Standards](#printing-a-list-of-installed-coding-standards)
9-
* [Listing Sniffs Inside a Coding Standard](#listing-sniffs-inside-a-coding-standard)
3+
<!-- START doctoc -->
4+
<!-- END doctoc -->
105

116
***
127

wiki/Version-3.0-Upgrade-Guide.md

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,8 @@ PHP_CodeSniffer version 3 contains a large number of core changes and breaks bac
77

88
## Table of contents
99

10-
* [Upgrading Custom Sniffs](#upgrading-custom-sniffs)
11-
* [Extending Other Sniffs](#extending-other-sniffs)
12-
* [Extending the Included Abstract Sniffs](#extending-the-included-abstract-sniffs)
13-
* [AbstractVariableSniff](#abstractvariablesniff)
14-
* [AbstractPatternSniff](#abstractpatternsniff)
15-
* [AbstractScopeSniff](#abstractscopesniff)
16-
* [New Class Names](#new-class-names)
17-
* [PHP_CodeSniffer_File](#php_codesniffer_file)
18-
* [PHP_CodeSniffer_Tokens](#php_codesniffer_tokens)
19-
* [PHP_CodeSniffer](#php_codesniffer)
20-
* [Upgrading Unit Tests](#upgrading-unit-tests)
21-
* [Setting CLI Values](#setting-cli-values)
22-
* [Upgrading Custom Reports](#upgrading-custom-reports)
23-
* [Supporting Concurrency](#supporting-concurrency)
10+
<!-- START doctoc -->
11+
<!-- END doctoc -->
2412

2513
***
2614

0 commit comments

Comments
 (0)