mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/Linter
synced 2024-11-23 23:44:17 +00:00
Initial commit
This configures a MediaWiki extension to recieve Parsoid's lint errors and expose them to users. Change-Id: Ie0776aecf145eb1c87c2a539ddf3ea8d35a899f5
This commit is contained in:
parent
44a0126f3a
commit
bce5b31616
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
.svn
|
||||||
|
*~
|
||||||
|
*.kate-swp
|
||||||
|
.*.swp
|
||||||
|
composer.lock
|
||||||
|
vendor
|
||||||
|
node_modules/
|
1
.jshintignore
Normal file
1
.jshintignore
Normal file
|
@ -0,0 +1 @@
|
||||||
|
node_modules
|
24
.jshintrc
Normal file
24
.jshintrc
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
// Enforcing
|
||||||
|
"bitwise": true,
|
||||||
|
"eqeqeq": true,
|
||||||
|
"freeze": true,
|
||||||
|
"latedef": true,
|
||||||
|
"noarg": true,
|
||||||
|
"nonew": true,
|
||||||
|
"undef": true,
|
||||||
|
"unused": true,
|
||||||
|
"strict": false,
|
||||||
|
|
||||||
|
// Relaxing
|
||||||
|
"es5": false,
|
||||||
|
|
||||||
|
// Environment
|
||||||
|
"browser": true,
|
||||||
|
"jquery": true,
|
||||||
|
|
||||||
|
"globals": {
|
||||||
|
"mediaWiki": false,
|
||||||
|
"OO": false
|
||||||
|
}
|
||||||
|
}
|
339
COPYING
Normal file
339
COPYING
Normal file
|
@ -0,0 +1,339 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Lesser General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License.
|
32
Gruntfile.js
Normal file
32
Gruntfile.js
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/*jshint node:true */
|
||||||
|
module.exports = function ( grunt ) {
|
||||||
|
grunt.loadNpmTasks( 'grunt-contrib-jshint' );
|
||||||
|
grunt.loadNpmTasks( 'grunt-jsonlint' );
|
||||||
|
grunt.loadNpmTasks( 'grunt-banana-checker' );
|
||||||
|
grunt.loadNpmTasks( 'grunt-jscs' );
|
||||||
|
var conf = grunt.file.readJSON( 'extension.json' );
|
||||||
|
|
||||||
|
grunt.initConfig( {
|
||||||
|
jshint: {
|
||||||
|
options: {
|
||||||
|
jshintrc: true
|
||||||
|
},
|
||||||
|
all: [
|
||||||
|
'modules/*.js'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
jscs: {
|
||||||
|
src: '<%= jshint.all %>'
|
||||||
|
},
|
||||||
|
banana: conf.MessagesDirs,
|
||||||
|
jsonlint: {
|
||||||
|
all: [
|
||||||
|
'**/*.json',
|
||||||
|
'!node_modules/**'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
grunt.registerTask( 'test', [ 'jshint', 'jscs', 'jsonlint', 'banana' ] );
|
||||||
|
grunt.registerTask( 'default', 'test' );
|
||||||
|
};
|
3
README
Normal file
3
README
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
Extension to help lint wiki pages. Currently designed to take advantage
|
||||||
|
of Parsoid's linter, could also be extended to linting JS or CSS in the
|
||||||
|
future.
|
15
composer.json
Normal file
15
composer.json
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"require-dev": {
|
||||||
|
"jakub-onderka/php-parallel-lint": "0.9",
|
||||||
|
"mediawiki/mediawiki-codesniffer": "0.8.0-alpha.1"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": [
|
||||||
|
"parallel-lint . --exclude vendor",
|
||||||
|
"phpcs -p -s"
|
||||||
|
],
|
||||||
|
"fix": [
|
||||||
|
"phpcbf"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
60
extension.json
Normal file
60
extension.json
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
{
|
||||||
|
"name": "Linter",
|
||||||
|
"license-name": "GPL-2.0+",
|
||||||
|
"url": "https://www.mediawiki.org/wiki/Extension:Linter",
|
||||||
|
"author": [
|
||||||
|
"Kunal Mehta"
|
||||||
|
],
|
||||||
|
"descriptionmsg": "linter-desc",
|
||||||
|
"type": "specialpage",
|
||||||
|
"AutoloadClasses": {
|
||||||
|
"MediaWiki\\Linter\\Hooks": "includes/Hooks.php",
|
||||||
|
"MediaWiki\\Linter\\Database": "includes/Database.php",
|
||||||
|
"MediaWiki\\Linter\\LintError": "includes/LintError.php",
|
||||||
|
"MediaWiki\\Linter\\ApiRecordLint": "includes/ApiRecordLint.php",
|
||||||
|
"MediaWiki\\Linter\\ApiQueryLintErrors": "includes/ApiQueryLintErrors.php",
|
||||||
|
"MediaWiki\\Linter\\SpecialLintErrors": "includes/SpecialLintErrors.php",
|
||||||
|
"MediaWiki\\Linter\\LintErrorsPager": "includes/LintErrorsPager.php"
|
||||||
|
},
|
||||||
|
"MessagesDirs": {
|
||||||
|
"Linter": "i18n"
|
||||||
|
},
|
||||||
|
"Hooks": {
|
||||||
|
"LoadExtensionSchemaUpdates": "MediaWiki\\Linter\\Hooks::onLoadExtensionSchemaUpdates",
|
||||||
|
"EditFormInitialText": "MediaWiki\\Linter\\Hooks::onEditFormInitialText"
|
||||||
|
},
|
||||||
|
"APIModules": {
|
||||||
|
"record-lint": "MediaWiki\\Linter\\ApiRecordLint"
|
||||||
|
},
|
||||||
|
"APIListModules": {
|
||||||
|
"linterrors": "MediaWiki\\Linter\\ApiQueryLintErrors"
|
||||||
|
},
|
||||||
|
"SpecialPages": {
|
||||||
|
"LintErrors": "MediaWiki\\Linter\\SpecialLintErrors"
|
||||||
|
},
|
||||||
|
"ResourceModules": {
|
||||||
|
"ext.linter.edit": {
|
||||||
|
"scripts": "ext.linter.edit.js",
|
||||||
|
"dependencies": [
|
||||||
|
"jquery.textSelection"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ResourceFileModulePaths": {
|
||||||
|
"localBasePath": "modules",
|
||||||
|
"remoteExtPath": "Linter/modules"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"LinterCategories": {
|
||||||
|
"fostered": true,
|
||||||
|
"obsolete-tag": true,
|
||||||
|
"bogus-image-options": true,
|
||||||
|
"missing-end-tag": true,
|
||||||
|
"stripped-tag": true
|
||||||
|
},
|
||||||
|
"LinterSubmitterWhitelist": {
|
||||||
|
"127.0.0.1": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"manifest_version": 1
|
||||||
|
}
|
38
i18n/en.json
Normal file
38
i18n/en.json
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Kunal Mehta"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"linterrors": "Lint errors",
|
||||||
|
"linterrors-subpage": "Lint errors: $1",
|
||||||
|
"linter-desc": "Track lint errors from an external service and show them to users",
|
||||||
|
"linter-pager-title": "Page title",
|
||||||
|
"linter-pager-template": "Through a template?",
|
||||||
|
"linter-pager-obsolete-tag-details": "Obsolete HTML tag",
|
||||||
|
"linter-pager-bogus-image-options-details": "Bogus file option",
|
||||||
|
"linter-pager-missing-end-tag-details": "Missing end tag",
|
||||||
|
"linter-pager-stripped-tag-details": "Stripped tag",
|
||||||
|
"linter-category-fostered": "Fostered content",
|
||||||
|
"linter-category-fostered-desc": "These pages have fostered content.",
|
||||||
|
"linter-category-obsolete-tag": "Obsolete HTML tags",
|
||||||
|
"linter-category-obsolete-tag-desc": "These pages use obsolete HTML tags.",
|
||||||
|
"linter-category-bogus-image-options": "Bogus file options",
|
||||||
|
"linter-category-bogus-image-options-desc": "These pages have files with bogus options.",
|
||||||
|
"linter-category-missing-end-tag": "Missing end tag",
|
||||||
|
"linter-category-missing-end-tag-desc": "These pages have missing end tags.",
|
||||||
|
"linter-category-stripped-tag": "Stripped tags",
|
||||||
|
"linter-category-stripped-tag-desc": "These pages have stripped tags.",
|
||||||
|
"linker-page-title-edit": "$1 ($2)",
|
||||||
|
"linker-page-edit": "edit",
|
||||||
|
"apihelp-query+linterrors-description": "Get a list of lint errors",
|
||||||
|
"apihelp-query+linterrors-param-category": "Category of lint errors",
|
||||||
|
"apihelp-query+linterrors-param-limit": "Number of results to query",
|
||||||
|
"apihelp-query+linterrors-param-from": "Lint ID to start querying from",
|
||||||
|
"apihelp-query+linterrors-param-namespace": "Only include lint errors from the specified namespaces",
|
||||||
|
"apihelp-query+linterrors-example-1": "Get all lint errors of the obsolete-tag category",
|
||||||
|
"apihelp-record-lint-description": "Record a lint error in the database",
|
||||||
|
"apihelp-record-lint-param-data": "JSON encoded data about the error",
|
||||||
|
"apihelp-record-lint-param-page": "Page title",
|
||||||
|
"apihelp-record-lint-param-revision": "Revision ID that the error was found in"
|
||||||
|
}
|
38
i18n/qqq.json
Normal file
38
i18n/qqq.json
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Kunal Mehta"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"linterrors": "{{doc-special|LintErrors}}",
|
||||||
|
"linterrors-subpage": "Page title for Special:LintErrors, $1 is the localized category description",
|
||||||
|
"linter-desc": "{{desc|name=Linter|url=https://www.mediawiki.org/wiki/Extension:Linter}}",
|
||||||
|
"linter-pager-title": "Table column heading for the column with page titles in it",
|
||||||
|
"linter-pager-template": "Table column heading for column with template title in it or an em dash if lint error is not inside a template",
|
||||||
|
"linter-pager-obsolete-tag-details": "Table column heading",
|
||||||
|
"linter-pager-bogus-image-options-details": "Table column heading",
|
||||||
|
"linter-pager-missing-end-tag-details": "Table column heading",
|
||||||
|
"linter-pager-stripped-tag-details": "Table column heading",
|
||||||
|
"linter-category-fostered": "Name of lint error category",
|
||||||
|
"linter-category-fostered-desc": "Description of category.",
|
||||||
|
"linter-category-obsolete-tag": "Name of lint error category",
|
||||||
|
"linter-category-obsolete-tag-desc": "Description of category.",
|
||||||
|
"linter-category-bogus-image-options": "Name of lint error category",
|
||||||
|
"linter-category-bogus-image-options-desc": "Description of category",
|
||||||
|
"linter-category-missing-end-tag": "Name of lint error category",
|
||||||
|
"linter-category-missing-end-tag-desc": "Description of category",
|
||||||
|
"linter-category-stripped-tag": "Name of lint error category",
|
||||||
|
"linter-category-stripped-tag-desc": "Description of category",
|
||||||
|
"linker-page-title-edit": "Used in a table cell. $1 is a link to the page, $2 is a link to edit that page, the link text is {{msg-mw|linker-page-edit}}",
|
||||||
|
"linker-page-edit": "Link text for edit link in {{msg-mw|linker-page-title-edit}} and {{msg-mw|linker-page-title-edit-template}}",
|
||||||
|
"apihelp-query+linterrors-description": "{{doc-apihelp-description|query+linterrors}}",
|
||||||
|
"apihelp-query+linterrors-param-category": "{{doc-apihelp-param|query+linterrors|category}}",
|
||||||
|
"apihelp-query+linterrors-param-limit": "{{doc-apihelp-param|query+linterrors|limit}}",
|
||||||
|
"apihelp-query+linterrors-param-from": "{{doc-apihelp-param|query+linterrors|from}}",
|
||||||
|
"apihelp-query+linterrors-param-namespace": "{{doc-apihelp-param|query+linterrors|namespace}}",
|
||||||
|
"apihelp-query+linterrors-example-1": "{{doc-apihelp-example|query+linterrors}}",
|
||||||
|
"apihelp-record-lint-description": "{{doc-apihelp-description|record-lint}}",
|
||||||
|
"apihelp-record-lint-param-data": "{{doc-apihelp-param|record-lint|data}}",
|
||||||
|
"apihelp-record-lint-param-page": "{{doc-apihelp-param|record-lint|page}}",
|
||||||
|
"apihelp-record-lint-param-revision": "{{doc-apihelp-param|record-lint|revision}}"
|
||||||
|
}
|
127
includes/ApiQueryLintErrors.php
Normal file
127
includes/ApiQueryLintErrors.php
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
* http://www.gnu.org/copyleft/gpl.html
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace MediaWiki\Linter;
|
||||||
|
|
||||||
|
use ApiBase;
|
||||||
|
use ApiQuery;
|
||||||
|
use ApiQueryBase;
|
||||||
|
use ApiResult;
|
||||||
|
use Title;
|
||||||
|
|
||||||
|
class ApiQueryLintErrors extends ApiQueryBase {
|
||||||
|
public function __construct( ApiQuery $queryModule, $moduleName ) {
|
||||||
|
parent::__construct( $queryModule, $moduleName, 'lnt' );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute() {
|
||||||
|
$params = $this->extractRequestParams();
|
||||||
|
|
||||||
|
$this->addTables( 'linter' );
|
||||||
|
if ( $params['category'] !== null ) {
|
||||||
|
$this->addWhereFld( 'linter_cat', $params['category'] );
|
||||||
|
} else {
|
||||||
|
// Limit only to enabled categories (there might be others in the DB)
|
||||||
|
$this->addWhereFld( 'linter_cat', $this->getCategories() );
|
||||||
|
}
|
||||||
|
$db = $this->getDB();
|
||||||
|
if ( $params['from'] !== null ) {
|
||||||
|
$this->addWhere( 'linter_id >= ' . $db->addQuotes( $params['from'] ) );
|
||||||
|
}
|
||||||
|
if ( $params['namespace'] !== null ) {
|
||||||
|
$this->addWhereFld( 'page_namespace', $params['namespace'] );
|
||||||
|
}
|
||||||
|
$this->addTables( 'page' );
|
||||||
|
$this->addJoinConds( [ 'page' => [ 'INNER JOIN', 'page_id=linter_page' ] ] );
|
||||||
|
$this->addFields( [
|
||||||
|
'linter_id', 'linter_cat', 'linter_params',
|
||||||
|
'page_namespace', 'page_title',
|
||||||
|
] );
|
||||||
|
// Be explicit about ORDER BY
|
||||||
|
$this->addOption( 'ORDER BY', 'linter_id' );
|
||||||
|
// Add +1 to limit to know if there's another row for continuation
|
||||||
|
$this->addOption( 'LIMIT', $params['limit'] + 1 );
|
||||||
|
$rows = $this->select( __METHOD__ );
|
||||||
|
$result = $this->getResult();
|
||||||
|
$count = 0;
|
||||||
|
foreach ( $rows as $row ) {
|
||||||
|
$lintError = Database::makeLintError( $row );
|
||||||
|
$count++;
|
||||||
|
if ( $count > $params['limit'] ) {
|
||||||
|
$this->setContinueEnumParameter( 'from', $lintError->lintId );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$title = Title::makeTitle( $row->page_namespace, $row->page_title );
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'title' => $title->getPrefixedText(),
|
||||||
|
'lintId' => $lintError->lintId,
|
||||||
|
'category' => $lintError->category,
|
||||||
|
'location' => $lintError->location,
|
||||||
|
'templateInfo' => $lintError->templateInfo,
|
||||||
|
'params' => $lintError->getExtraParams(),
|
||||||
|
];
|
||||||
|
// template info and params are an object
|
||||||
|
$data['params'][ApiResult::META_TYPE] = 'assoc';
|
||||||
|
$data['templateInfo'][ApiResult::META_TYPE] = 'assoc';
|
||||||
|
|
||||||
|
$fit = $result->addValue( [ 'query', $this->getModuleName() ], null, $data );
|
||||||
|
if ( !$fit ) {
|
||||||
|
$this->setContinueEnumParameter( 'from', $lintError->lintId );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getCategories() {
|
||||||
|
global $wgLinterCategories;
|
||||||
|
return array_keys( array_filter( $wgLinterCategories ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAllowedParams() {
|
||||||
|
return [
|
||||||
|
'category' => [
|
||||||
|
ApiBase::PARAM_TYPE => $this->getCategories(),
|
||||||
|
ApiBase::PARAM_ISMULTI => true,
|
||||||
|
],
|
||||||
|
'limit' => [
|
||||||
|
ApiBase::PARAM_DFLT => 10,
|
||||||
|
ApiBase::PARAM_TYPE => 'limit',
|
||||||
|
ApiBase::PARAM_MIN => 1,
|
||||||
|
ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1,
|
||||||
|
ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2
|
||||||
|
],
|
||||||
|
'namespace' => [
|
||||||
|
ApiBase::PARAM_TYPE => 'namespace',
|
||||||
|
ApiBase::PARAM_ISMULTI => true,
|
||||||
|
],
|
||||||
|
'from' => [
|
||||||
|
ApiBase::PARAM_TYPE => 'integer',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExamplesMessages() {
|
||||||
|
return [
|
||||||
|
'action=query&list=linterrors&lecategory=obsolete-tag' =>
|
||||||
|
'apihelp-query+linterrors-example-1',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
86
includes/ApiRecordLint.php
Normal file
86
includes/ApiRecordLint.php
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
* http://www.gnu.org/copyleft/gpl.html
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace MediaWiki\Linter;
|
||||||
|
|
||||||
|
use ApiBase;
|
||||||
|
use FormatJson;
|
||||||
|
use IPSet\IPSet;
|
||||||
|
use Title;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API module for an external service to record
|
||||||
|
* a lint error
|
||||||
|
*/
|
||||||
|
class ApiRecordLint extends ApiBase {
|
||||||
|
|
||||||
|
public function execute() {
|
||||||
|
global $wgLinterSubmitterWhitelist;
|
||||||
|
|
||||||
|
$ipSet = new IPSet(
|
||||||
|
array_keys( array_filter( $wgLinterSubmitterWhitelist ) )
|
||||||
|
);
|
||||||
|
if ( !$ipSet->match( $this->getRequest()->getIP() ) ) {
|
||||||
|
$this->dieUsage(
|
||||||
|
'Your IP address has not been whitelisted to report lint errors',
|
||||||
|
'invalid-ip'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$params = $this->extractRequestParams();
|
||||||
|
$data = FormatJson::decode( $params['data'], true );
|
||||||
|
if ( !is_array( $data ) ) {
|
||||||
|
$this->dieUsage( 'Invalid data', 'invalid-data' );
|
||||||
|
}
|
||||||
|
|
||||||
|
$errors = [];
|
||||||
|
$title = Title::newFromText( $params['page'] );
|
||||||
|
if ( !$title || !$title->getArticleID()
|
||||||
|
|| $title->getLatestRevID() != $params['revision']
|
||||||
|
) {
|
||||||
|
$this->dieUsage( 'Invalid, non-existent, or outdated title', 'invalid-title' );
|
||||||
|
}
|
||||||
|
foreach ( $data as $info ) {
|
||||||
|
$info['params']['location'] = array_slice( $info['dsr'], 0, 2 );
|
||||||
|
if ( isset( $info['templateInfo'] ) && $info['templateInfo'] ) {
|
||||||
|
$info['params']['templateInfo'] = $info['templateInfo'];
|
||||||
|
}
|
||||||
|
$errors[] = new LintError(
|
||||||
|
$info['type'],
|
||||||
|
$info['params']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$lintDb = new Database( $title->getArticleID() );
|
||||||
|
$result = $lintDb->setForPage( $errors );
|
||||||
|
$this->getResult()->addValue( $this->getModuleName(), 'success', $result );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isInternal() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAllowedParams() {
|
||||||
|
return [
|
||||||
|
'data' => 'string',
|
||||||
|
'page' => 'string',
|
||||||
|
'revision' => 'int',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
191
includes/Database.php
Normal file
191
includes/Database.php
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
* http://www.gnu.org/copyleft/gpl.html
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace MediaWiki\Linter;
|
||||||
|
|
||||||
|
use DBAccessObjectUtils;
|
||||||
|
use IDBAccessObject;
|
||||||
|
use FormatJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database logic
|
||||||
|
*/
|
||||||
|
class Database implements IDBAccessObject {
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $pageId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $pageId
|
||||||
|
*/
|
||||||
|
public function __construct( $pageId ) {
|
||||||
|
$this->pageId = $pageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a specific LintError by id
|
||||||
|
*
|
||||||
|
* @param int $id linter_id
|
||||||
|
* @param int $flags
|
||||||
|
* @return bool|LintError
|
||||||
|
*/
|
||||||
|
public function getFromId( $id, $flags = 0 ) {
|
||||||
|
list( $index, $options ) = DBAccessObjectUtils::getDBOptions( $flags );
|
||||||
|
$row = wfGetDB( $index )->selectRow(
|
||||||
|
'linter',
|
||||||
|
[ 'linter_cat', 'linter_params' ],
|
||||||
|
[ 'linter_id' => $id, 'linter_page' => $this->pageId ],
|
||||||
|
__METHOD__,
|
||||||
|
$options
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( $row ) {
|
||||||
|
$row->linter_id = $id;
|
||||||
|
return $this->makeLintError( $row );
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turn a database row into a LintError object
|
||||||
|
*
|
||||||
|
* @param \stdClass $row
|
||||||
|
* @return LintError
|
||||||
|
*/
|
||||||
|
public static function makeLintError( $row ) {
|
||||||
|
return new LintError(
|
||||||
|
$row->linter_cat,
|
||||||
|
$row->linter_params,
|
||||||
|
(int)$row->linter_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the lint errors for a page
|
||||||
|
*
|
||||||
|
* @param int $flags
|
||||||
|
* @return LintError[]
|
||||||
|
*/
|
||||||
|
public function getForPage( $flags = 0 ) {
|
||||||
|
list( $index, $options ) = DBAccessObjectUtils::getDBOptions( $flags );
|
||||||
|
$rows = wfGetDB( $index )->select(
|
||||||
|
'linter',
|
||||||
|
[ 'linter_id', 'linter_cat', 'linter_params' ],
|
||||||
|
[ 'linter_page' => $this->pageId ],
|
||||||
|
__METHOD__,
|
||||||
|
$options
|
||||||
|
);
|
||||||
|
$result = [];
|
||||||
|
foreach ( $rows as $row ) {
|
||||||
|
$error = $this->makeLintError( $row );
|
||||||
|
$result[$error->id()] = $error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a LintError object into an array for
|
||||||
|
* inserting/querying in the database
|
||||||
|
*
|
||||||
|
* @param LintError $error
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function serializeError( LintError $error ) {
|
||||||
|
if ( $error->lintId !== 0 ) {
|
||||||
|
return [
|
||||||
|
'linter_id' => $error->lintId,
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
return [
|
||||||
|
'linter_page' => $this->pageId,
|
||||||
|
'linter_cat' => $error->category,
|
||||||
|
'linter_params' => FormatJson::encode( $error->params, false, FormatJson::ALL_OK ),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the specified lint errors in the
|
||||||
|
* database
|
||||||
|
*
|
||||||
|
* @param LintError[] $errors
|
||||||
|
* @return array [ 'deleted' => int|bool, 'added' => int ]
|
||||||
|
*/
|
||||||
|
public function setForPage( $errors ) {
|
||||||
|
$previous = $this->getForPage( self::READ_LATEST );
|
||||||
|
$dbw = wfGetDB( DB_MASTER );
|
||||||
|
if ( !$previous && !$errors ) {
|
||||||
|
return [ 'deleted' => 0, 'added' => 0 ];
|
||||||
|
} elseif ( !$previous && $errors ) {
|
||||||
|
$toInsert = $errors;
|
||||||
|
$toDelete = [];
|
||||||
|
} elseif ( $previous && !$errors ) {
|
||||||
|
$dbw->delete(
|
||||||
|
'linter',
|
||||||
|
[ 'linter_page' => $this->pageId ],
|
||||||
|
__METHOD__
|
||||||
|
);
|
||||||
|
return [ 'deleted' => true, 'added' => 0 ];
|
||||||
|
} else {
|
||||||
|
$toInsert = [];
|
||||||
|
$toDelete = $previous;
|
||||||
|
// Diff previous and errors
|
||||||
|
foreach ( $errors as $error ) {
|
||||||
|
$uniqueId = $error->id();
|
||||||
|
if ( isset( $previous[$uniqueId] ) ) {
|
||||||
|
unset( $toDelete[$uniqueId] );
|
||||||
|
} else {
|
||||||
|
$toInsert[] = $error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $toDelete ) {
|
||||||
|
$ids = [];
|
||||||
|
foreach ( $toDelete as $lintError ) {
|
||||||
|
if ( $lintError->lintId ) {
|
||||||
|
$ids[] = $lintError->lintId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$dbw->delete(
|
||||||
|
'linter',
|
||||||
|
[ 'linter_id' => $ids ],
|
||||||
|
__METHOD__
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $toInsert ) {
|
||||||
|
$dbw->insert(
|
||||||
|
'linter',
|
||||||
|
array_map( [ $this, 'serializeError' ], $toInsert ),
|
||||||
|
__METHOD__
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'deleted' => count( $toDelete ),
|
||||||
|
'added' => count( $toInsert ),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
66
includes/Hooks.php
Normal file
66
includes/Hooks.php
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
* http://www.gnu.org/copyleft/gpl.html
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace MediaWiki\Linter;
|
||||||
|
|
||||||
|
use DatabaseUpdater;
|
||||||
|
use EditPage;
|
||||||
|
|
||||||
|
class Hooks {
|
||||||
|
/**
|
||||||
|
* @param DatabaseUpdater $updater
|
||||||
|
*/
|
||||||
|
public static function onLoadExtensionSchemaUpdates( DatabaseUpdater $updater ) {
|
||||||
|
$updater->addExtensionTable(
|
||||||
|
'linter', dirname( __DIR__ ) . '/linter.sql'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook: EditFormInitialText
|
||||||
|
*
|
||||||
|
* If there is a lintid parameter, look up that error in the database
|
||||||
|
* and setup and output our client-side helpers
|
||||||
|
*
|
||||||
|
* @param EditPage $editPage
|
||||||
|
*/
|
||||||
|
public static function onEditFormInitialText( EditPage $editPage ) {
|
||||||
|
$context = $editPage->getContext();
|
||||||
|
$request = $context->getRequest();
|
||||||
|
$lintId = $request->getInt( 'lintid' );
|
||||||
|
if ( !$lintId ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$title = $editPage->getTitle();
|
||||||
|
|
||||||
|
$lintError = ( new Database( $title->getArticleID() ) )->getFromId( $lintId );
|
||||||
|
if ( !$lintError ) {
|
||||||
|
// Already fixed or bogus URL parameter?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$out = $context->getOutput();
|
||||||
|
$out->addJsConfigVars( [
|
||||||
|
'wgLinterErrorCategory' => $lintError->category,
|
||||||
|
'wgLinterErrorLocation' => $lintError->location,
|
||||||
|
] );
|
||||||
|
$out->addModules( 'ext.linter.edit' );
|
||||||
|
}
|
||||||
|
}
|
105
includes/LintError.php
Normal file
105
includes/LintError.php
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
* http://www.gnu.org/copyleft/gpl.html
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace MediaWiki\Linter;
|
||||||
|
|
||||||
|
use FormatJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model to represent a LintError
|
||||||
|
*/
|
||||||
|
class LintError {
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $category;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int[] [ start, end ]
|
||||||
|
*/
|
||||||
|
public $location;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $lintId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $params;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $templateInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $category
|
||||||
|
* @param string|array $params JSON string or already decoded array
|
||||||
|
* @param int $lintId linter_id
|
||||||
|
*/
|
||||||
|
public function __construct( $category, $params, $lintId = 0 ) {
|
||||||
|
$this->category = $category;
|
||||||
|
if ( is_string( $params ) ) {
|
||||||
|
$params = FormatJson::decode( $params, true );
|
||||||
|
}
|
||||||
|
$this->params = $params;
|
||||||
|
$this->lintId = $lintId;
|
||||||
|
// Convenient accessors for all errors
|
||||||
|
$this->location = $params['location'];
|
||||||
|
$this->templateInfo = isset( $params['templateInfo'] )
|
||||||
|
? $params['templateInfo'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param LintError $other
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function equals( LintError $other ) {
|
||||||
|
return $this->category === $other->category
|
||||||
|
&& $this->params === $other->params;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unique id to identify this error, for internal
|
||||||
|
* purposes
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function id() {
|
||||||
|
return $this->category . FormatJson::encode( $this->params );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the params that are extra for this error,
|
||||||
|
* not part of the default set
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getExtraParams() {
|
||||||
|
$params = $this->params;
|
||||||
|
unset( $params['templateInfo'] );
|
||||||
|
unset( $params['location'] );
|
||||||
|
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
137
includes/LintErrorsPager.php
Normal file
137
includes/LintErrorsPager.php
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
* http://www.gnu.org/copyleft/gpl.html
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace MediaWiki\Linter;
|
||||||
|
|
||||||
|
use IContextSource;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use LinkCache;
|
||||||
|
use Html;
|
||||||
|
use MediaWiki\Linker\LinkRenderer;
|
||||||
|
use MediaWiki\MediaWikiServices;
|
||||||
|
use TablePager;
|
||||||
|
use TitleValue;
|
||||||
|
use Title;
|
||||||
|
|
||||||
|
class LintErrorsPager extends TablePager {
|
||||||
|
|
||||||
|
private $category;
|
||||||
|
/**
|
||||||
|
* @var LinkRenderer
|
||||||
|
*/
|
||||||
|
private $linkRenderer;
|
||||||
|
|
||||||
|
public function __construct( IContextSource $context, $category, LinkRenderer $linkRenderer ) {
|
||||||
|
$this->category = $category;
|
||||||
|
$this->linkRenderer = $linkRenderer;
|
||||||
|
parent::__construct( $context );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQueryInfo() {
|
||||||
|
return [
|
||||||
|
'tables' => [ 'page', 'linter' ],
|
||||||
|
'fields' => array_merge(
|
||||||
|
LinkCache::getSelectFields(),
|
||||||
|
[
|
||||||
|
'page_namespace', 'page_title',
|
||||||
|
'linter_id', 'linter_params',
|
||||||
|
]
|
||||||
|
),
|
||||||
|
'conds' => [ 'linter_cat' => $this->category ],
|
||||||
|
'join_conds' => [ 'page' => [ 'INNER JOIN', 'page_id=linter_page' ] ]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function doBatchLookups() {
|
||||||
|
$linkCache = MediaWikiServices::getInstance()->getLinkCache();
|
||||||
|
foreach ( $this->mResult as $row ) {
|
||||||
|
$titleValue = new TitleValue( (int)$row->page_namespace, $row->page_title );
|
||||||
|
$linkCache->addGoodLinkObjFromRow( $titleValue, $row );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isFieldSortable( $field ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function formatValue( $name, $value ) {
|
||||||
|
$row = $this->mCurrentRow;
|
||||||
|
$row->linter_cat = $this->category;
|
||||||
|
$lintError = Database::makeLintError( $row );
|
||||||
|
switch ( $name ) {
|
||||||
|
case 'title':
|
||||||
|
$title = Title::makeTitle( $row->page_namespace, $row->page_title );
|
||||||
|
$viewLink = $this->linkRenderer->makeLink( $title );
|
||||||
|
if ( !$title->quickUserCan( 'edit', $this->getUser() ) ) {
|
||||||
|
return $viewLink;
|
||||||
|
}
|
||||||
|
$editLink = $this->linkRenderer->makeLink(
|
||||||
|
$title,
|
||||||
|
$this->msg( 'linker-page-edit' )->text(),
|
||||||
|
[],
|
||||||
|
[ 'action' => 'edit', 'lintid' => $lintError->lintId, ]
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->msg( 'linker-page-title-edit' )->rawParams( $viewLink, $editLink )->escaped();
|
||||||
|
case 'details':
|
||||||
|
if ( $this->category === 'obsolete-tag' && isset( $lintError->params['name'] ) ) {
|
||||||
|
return Html::element( 'code', [], $lintError->params['name'] );
|
||||||
|
} elseif ( $this->category === 'bogus-image-options' && isset( $lintError->params['items'] ) ) {
|
||||||
|
$list = array_map( function( $in ) {
|
||||||
|
return Html::element( 'code', [], $in );
|
||||||
|
}, $lintError->params['items'] );
|
||||||
|
return $this->getLanguage()->commaList( $list );
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
case 'template':
|
||||||
|
if ( !$lintError->templateInfo ) {
|
||||||
|
return '—';
|
||||||
|
}
|
||||||
|
$templateName = $lintError->templateInfo['name'];
|
||||||
|
$templateTitle = Title::newFromText( $templateName, NS_TEMPLATE );
|
||||||
|
if ( !$templateTitle ) {
|
||||||
|
// Shouldn't be possible...???
|
||||||
|
return '&mdash';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->linkRenderer->makeLink(
|
||||||
|
$templateTitle
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
throw new InvalidArgumentException( "Unexpected name: $name" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDefaultSort() {
|
||||||
|
return 'linter_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFieldNames() {
|
||||||
|
$names = [
|
||||||
|
'title' => $this->msg( 'linter-pager-title' ),
|
||||||
|
];
|
||||||
|
if ( $this->category !== 'fostered' ) {
|
||||||
|
// TODO: don't hardcode list of stuff with no parameters...?
|
||||||
|
$names['details'] = $this->msg( "linter-pager-{$this->category}-details" );
|
||||||
|
}
|
||||||
|
$names['template'] = $this->msg( "linter-pager-template" );
|
||||||
|
return $names;
|
||||||
|
}
|
||||||
|
}
|
88
includes/SpecialLintErrors.php
Normal file
88
includes/SpecialLintErrors.php
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
* http://www.gnu.org/copyleft/gpl.html
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace MediaWiki\Linter;
|
||||||
|
|
||||||
|
use Html;
|
||||||
|
use SpecialPage;
|
||||||
|
|
||||||
|
class SpecialLintErrors extends SpecialPage {
|
||||||
|
|
||||||
|
private $category;
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
parent::__construct( 'LintErrors' );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getCategories() {
|
||||||
|
global $wgLinterCategories;
|
||||||
|
return array_keys( array_filter( $wgLinterCategories ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute( $par ) {
|
||||||
|
$this->setHeaders();
|
||||||
|
$this->outputHeader();
|
||||||
|
$cats = $this->getCategories();
|
||||||
|
if ( in_array( $par, $cats ) ) {
|
||||||
|
$this->category = $par;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !$this->category ) {
|
||||||
|
$this->addHelpLink( 'Help:Extension:Linter' );
|
||||||
|
$this->showCategoryList( $cats );
|
||||||
|
} else {
|
||||||
|
$this->addHelpLink( "Help:Extension:Linter/{$this->category}" );
|
||||||
|
$out = $this->getOutput();
|
||||||
|
$out->setPageTitle(
|
||||||
|
$this->msg( 'linterrors-subpage',
|
||||||
|
$this->msg( "linter-category-{$this->category}" )->text()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$out->addBacklinkSubtitle( $this->getPageTitle() );
|
||||||
|
$out->addWikiMsg( "linter-category-{$this->category}-desc" );
|
||||||
|
$pager = new LintErrorsPager(
|
||||||
|
$this->getContext(), $this->category, $this->getLinkRenderer()
|
||||||
|
);
|
||||||
|
$out->addParserOutput( $pager->getFullOutput() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function showCategoryList( array $cats ) {
|
||||||
|
$linkRenderer = $this->getLinkRenderer();
|
||||||
|
$html = Html::openElement( 'ul' ) . "\n";
|
||||||
|
sort( $cats );
|
||||||
|
foreach ( $cats as $cat ) {
|
||||||
|
$html .= Html::rawElement( 'li', [], $linkRenderer->makeKnownLink(
|
||||||
|
$this->getPageTitle( $cat ),
|
||||||
|
$this->msg( "linter-category-$cat" )->text()
|
||||||
|
) ) . "\n";
|
||||||
|
}
|
||||||
|
$html .= Html::closeElement( 'ul' );
|
||||||
|
$this->getOutput()->addHTML( $html );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGroupName() {
|
||||||
|
return 'maintenance';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
13
linter.sql
Normal file
13
linter.sql
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
CREATE TABLE /*_*/linter (
|
||||||
|
-- primary key
|
||||||
|
linter_id int UNSIGNED AUTO_INCREMENT PRIMARY KEY not null,
|
||||||
|
-- page id
|
||||||
|
linter_page int UNSIGNED not null,
|
||||||
|
-- error category
|
||||||
|
linter_cat VARCHAR(30) not null,
|
||||||
|
-- extra parameters about the error, JSON encoded
|
||||||
|
linter_params blob NOT NULL
|
||||||
|
) /*$wgDBTableOptions*/;
|
||||||
|
|
||||||
|
-- Query by page
|
||||||
|
CREATE INDEX /*i*/linter_page ON /*_*/linter (linter_page);
|
8
modules/ext.linter.edit.js
Normal file
8
modules/ext.linter.edit.js
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
( function ( mw, $ ) {
|
||||||
|
$( function () {
|
||||||
|
var location = mw.config.get( 'wgLinterErrorLocation' );
|
||||||
|
if ( location ) {
|
||||||
|
$( '#wpTextbox1' ).focus().textSelection( 'setSelection', { start: location[ 0 ], end: location[ 1 ] } );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}( mediaWiki, jQuery ) );
|
13
package.json
Normal file
13
package.json
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"scripts": {
|
||||||
|
"test": "grunt test"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"grunt": "0.4.5",
|
||||||
|
"grunt-cli": "0.1.13",
|
||||||
|
"grunt-contrib-jshint": "0.11.3",
|
||||||
|
"grunt-banana-checker": "0.4.0",
|
||||||
|
"grunt-jscs": "2.2.0",
|
||||||
|
"grunt-jsonlint": "1.0.7"
|
||||||
|
}
|
||||||
|
}
|
14
phpcs.xml
Normal file
14
phpcs.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<ruleset>
|
||||||
|
<rule ref="vendor/mediawiki/mediawiki-codesniffer/MediaWiki"/>
|
||||||
|
<file>.</file>
|
||||||
|
<rule ref="MediaWiki.Commenting.FunctionComment.Missing">
|
||||||
|
<severity>0</severity>
|
||||||
|
</rule>
|
||||||
|
<rule ref="MediaWiki.Commenting.FunctionComment.MissingParamComment">
|
||||||
|
<severity>0</severity>
|
||||||
|
</rule>
|
||||||
|
<arg name="extensions" value="php,php5,inc"/>
|
||||||
|
<arg name="encoding" value="utf8"/>
|
||||||
|
<exclude-pattern>vendor</exclude-pattern>
|
||||||
|
</ruleset>
|
Loading…
Reference in a new issue