mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/CodeMirror
synced 2024-09-24 02:38:22 +00:00
build: Replace jshint/jscs with eslint, introduce stylelint
Change-Id: I9b5afb39f5a0d32e722b2a1f56c219b8c85b451c
This commit is contained in:
parent
a6427ea4c9
commit
66ba217ba2
15
.eslintrc.json
Normal file
15
.eslintrc.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"extends": "wikimedia",
|
||||
"env": {
|
||||
"browser": true,
|
||||
"jquery": true,
|
||||
"qunit": true
|
||||
},
|
||||
"globals": {
|
||||
"mediaWiki": false,
|
||||
"CodeMirror": false
|
||||
},
|
||||
"rules": {
|
||||
"dot-notation": [ "error", { "allowKeywords": true } ]
|
||||
}
|
||||
}
|
6
.jscsrc
6
.jscsrc
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"preset": "wikimedia",
|
||||
"requireVarDeclFirst": null,
|
||||
"requireMultipleVarDecl": null,
|
||||
"disallowEmptyBlocks": null
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
node_modules
|
||||
vendor
|
||||
# upstream libs
|
||||
resources/lib/
|
25
.jshintrc
25
.jshintrc
|
@ -1,25 +0,0 @@
|
|||
{
|
||||
// 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,
|
||||
"CodeMirror": false,
|
||||
"mod": false
|
||||
}
|
||||
}
|
3
.stylelintrc
Normal file
3
.stylelintrc
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"extends": "stylelint-config-wikimedia"
|
||||
}
|
23
Gruntfile.js
23
Gruntfile.js
|
@ -1,23 +1,24 @@
|
|||
/*jshint node:true */
|
||||
/* eslint-env node, es6 */
|
||||
module.exports = function ( grunt ) {
|
||||
grunt.loadNpmTasks( 'grunt-contrib-jshint' );
|
||||
grunt.loadNpmTasks( 'grunt-jsonlint' );
|
||||
grunt.loadNpmTasks( 'grunt-banana-checker' );
|
||||
grunt.loadNpmTasks( 'grunt-jscs' );
|
||||
grunt.loadNpmTasks( 'grunt-eslint' );
|
||||
grunt.loadNpmTasks( 'grunt-jsonlint' );
|
||||
grunt.loadNpmTasks( 'grunt-stylelint' );
|
||||
|
||||
grunt.initConfig( {
|
||||
jshint: {
|
||||
options: {
|
||||
jshintrc: true
|
||||
},
|
||||
eslint: {
|
||||
all: [
|
||||
'**/*.js',
|
||||
'!resources/lib/**',
|
||||
'!node_modules/**'
|
||||
]
|
||||
},
|
||||
jscs: {
|
||||
src: '<%= jshint.all %>'
|
||||
stylelint: {
|
||||
all: [
|
||||
'**/*.css',
|
||||
'!resources/lib/**',
|
||||
'!node_modules/**'
|
||||
]
|
||||
},
|
||||
banana: {
|
||||
all: 'i18n/'
|
||||
|
@ -30,6 +31,6 @@ module.exports = function ( grunt ) {
|
|||
}
|
||||
} );
|
||||
|
||||
grunt.registerTask( 'test', [ 'jshint', 'jscs', 'jsonlint', 'banana' ] );
|
||||
grunt.registerTask( 'test', [ 'eslint', 'stylelint', 'jsonlint', 'banana' ] );
|
||||
grunt.registerTask( 'default', 'test' );
|
||||
};
|
||||
|
|
13
package.json
13
package.json
|
@ -3,11 +3,12 @@
|
|||
"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.5.0",
|
||||
"grunt-jsonlint": "1.0.7"
|
||||
"eslint-config-wikimedia": "0.3.0",
|
||||
"grunt": "1.0.1",
|
||||
"grunt-banana-checker": "0.5.0",
|
||||
"grunt-eslint": "19.0.0",
|
||||
"grunt-jsonlint": "1.1.0",
|
||||
"grunt-stylelint": "0.7.0",
|
||||
"stylelint-config-wikimedia": "0.4.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,30 @@
|
|||
( function ( mw, $ ) {
|
||||
var origTextSelection, codeMirror, api, originHooksTextarea;
|
||||
|
||||
if ( mw.config.get( 'wgCodeEditorCurrentLanguage' ) ) { // If the CodeEditor is used then just exit;
|
||||
return;
|
||||
}
|
||||
|
||||
// codeMirror needs a special textselection jQuery function to work, save the current one to restore when
|
||||
// CodeMirror get's disabled.
|
||||
var origTextSelection = $.fn.textSelection,
|
||||
codeMirror = mw.user.options.get( 'usecodemirror' ) === '1' || mw.user.options.get( 'usecodemirror' ) === 1,
|
||||
api = new mw.Api(),
|
||||
origTextSelection = $.fn.textSelection;
|
||||
codeMirror = mw.user.options.get( 'usecodemirror' ) === '1' || mw.user.options.get( 'usecodemirror' ) === 1;
|
||||
api = new mw.Api();
|
||||
originHooksTextarea = $.valHooks.textarea;
|
||||
|
||||
// function for a textselection function for CodeMirror
|
||||
cmTextSelection = function ( command, options ) {
|
||||
function cmTextSelection( command, options ) {
|
||||
var fn, retval;
|
||||
|
||||
if ( !codeMirror || codeMirror.getTextArea() !== this[ 0 ] ) {
|
||||
return origTextSelection.call( this, command, options );
|
||||
}
|
||||
var fn, retval;
|
||||
|
||||
fn = {
|
||||
/**
|
||||
* Get the contents of the textarea
|
||||
*
|
||||
* @return {string}
|
||||
*/
|
||||
getContents: function () {
|
||||
return codeMirror.doc.getValue();
|
||||
|
@ -30,6 +37,8 @@
|
|||
/**
|
||||
* Get the currently selected text in this textarea. Will focus the textarea
|
||||
* in some browsers (IE/Opera)
|
||||
*
|
||||
* @return {string}
|
||||
*/
|
||||
getSelection: function () {
|
||||
return codeMirror.doc.getSelection();
|
||||
|
@ -38,6 +47,9 @@
|
|||
/**
|
||||
* Inserts text at the beginning and end of a text selection, optionally
|
||||
* inserting text at the caret when selection is empty.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @return {jQuery}
|
||||
*/
|
||||
encapsulateSelection: function ( options ) {
|
||||
return this.each( function () {
|
||||
|
@ -78,6 +90,11 @@
|
|||
* Do the splitlines stuff.
|
||||
*
|
||||
* Wrap each line of the selected text with pre and post
|
||||
*
|
||||
* @param {string} selText
|
||||
* @param {string} pre
|
||||
* @param {string} post
|
||||
* @return {string}
|
||||
*/
|
||||
function doSplitLines( selText, pre, post ) {
|
||||
var i,
|
||||
|
@ -126,6 +143,9 @@
|
|||
/**
|
||||
* Get the position (in resolution of bytes not necessarily characters)
|
||||
* in a textarea
|
||||
*
|
||||
* @param {Object} options
|
||||
* @return {number}
|
||||
*/
|
||||
getCaretPosition: function ( options ) {
|
||||
var caretPos = codeMirror.doc.indexFromPos( codeMirror.doc.getCursor( true ) ),
|
||||
|
@ -145,6 +165,8 @@
|
|||
/**
|
||||
* Scroll a textarea to the current cursor position. You can set the cursor
|
||||
* position with setSelection()
|
||||
*
|
||||
* @return {jQuery}
|
||||
*/
|
||||
scrollToCaretPosition: function () {
|
||||
return this.each( function () {
|
||||
|
@ -208,13 +230,15 @@
|
|||
codeMirror.focus();
|
||||
|
||||
return retval;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the CodeMirror button to WikiEditor
|
||||
*/
|
||||
addCodeMirrorToWikiEditor = function () {
|
||||
function addCodeMirrorToWikiEditor() {
|
||||
var msg;
|
||||
if ( $( '#wikiEditor-section-main' ).length > 0 ) {
|
||||
var msg = codeMirror ? 'codemirror-disable-label' : 'codemirror-enable-label';
|
||||
msg = codeMirror ? 'codemirror-disable-label' : 'codemirror-enable-label';
|
||||
|
||||
$( '#wpTextbox1' ).wikiEditor(
|
||||
'addToToolbar',
|
||||
|
@ -231,6 +255,7 @@
|
|||
action: {
|
||||
type: 'callback',
|
||||
execute: function ( context ) {
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
switchCodeMirror( context );
|
||||
}
|
||||
}
|
||||
|
@ -241,8 +266,7 @@
|
|||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
originHooksTextarea = $.valHooks.textarea;
|
||||
}
|
||||
|
||||
// define JQuery hook for searching and replacing text using JS if CodeMirror is enabled, see Bug: T108711
|
||||
$.valHooks.textarea = {
|
||||
|
@ -308,6 +332,7 @@
|
|||
.attr( 'src', $src )
|
||||
.attr( 'title', mw.msg( 'codemirror-enable-label' ) );
|
||||
} else {
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
enableCodeMirror();
|
||||
$src = mw.config.get( 'wgExtensionAssetsPath' ) + '/CodeMirror/resources/images/' + ( context ? 'cm-on.png' : 'old-cm-on.png' );
|
||||
$img
|
||||
|
@ -356,6 +381,7 @@
|
|||
if ( $.inArray( mw.config.get( 'wgAction' ), [ 'edit', 'submit' ] ) !== -1 ) {
|
||||
// This function shouldn't be called without user.options is loaded, but it's not guaranteed
|
||||
mw.loader.using( 'user.options', function () {
|
||||
var $image;
|
||||
// This can be the string "0" if the user disabled the preference - Bug T54542#555387
|
||||
if ( mw.user.options.get( 'usebetatoolbar' ) === 1 || mw.user.options.get( 'usebetatoolbar' ) === '1' ) {
|
||||
// load wikiEditor's toolbar (if not already) and add our button
|
||||
|
@ -364,7 +390,7 @@
|
|||
).then( addCodeMirrorToWikiEditor );
|
||||
} else {
|
||||
// If WikiEditor isn't enabled, add CodeMirror button to the default wiki editor toolbar
|
||||
var $image = $( '<img>' ).attr( {
|
||||
$image = $( '<img>' ).attr( {
|
||||
width: 23,
|
||||
height: 22,
|
||||
src: mw.config.get( 'wgExtensionAssetsPath' ) + '/CodeMirror/resources/images/old-cm-' + ( codeMirror ? 'on.png' : 'off.png' ),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.CodeMirror {
|
||||
border: 1px solid #CCC;
|
||||
border: 1px solid #ccc;
|
||||
font-size: medium;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
@ -8,14 +8,17 @@
|
|||
font-size: small;
|
||||
}
|
||||
|
||||
/* stylelint-disable block-opening-brace-newline-before, block-opening-brace-newline-after,
|
||||
block-closing-brace-space-after, declaration-block-single-line-max-declarations,
|
||||
declaration-block-semicolon-newline-after, selector-list-comma-newline-after */
|
||||
|
||||
.cm-mw-pagename { text-decoration: underline; }
|
||||
|
||||
.cm-mw-matching {background-color: gold;}
|
||||
.cm-mw-matching { background-color: #ffd700; }
|
||||
|
||||
.cm-mw-skipformatting { background-color: #adf; }
|
||||
.cm-mw-list { color: #08f; font-weight: bold; background-color: #eee; }
|
||||
.cm-mw-signature,
|
||||
.cm-mw-hr { color: #08f; font-weight: bold; background-color: #eee; }
|
||||
.cm-mw-signature, .cm-mw-hr { color: #08f; font-weight: bold; background-color: #eee; }
|
||||
.cm-mw-indenting { color: #08f; font-weight: bold; background-color: #ddd; }
|
||||
.cm-mw-mnemonic { color: #090; }
|
||||
.cm-mw-comment { color: #aaa; font-weight: normal; }
|
||||
|
@ -62,12 +65,12 @@ pre.cm-mw-tag-nowiki, .cm-mw-tag-nowiki {background-image: url(img/black4.png);}
|
|||
.cm-mw-link-pagename { color: #219; font-weight: normal; }
|
||||
.cm-mw-link-tosection { color: #08f; font-weight: normal; }
|
||||
.cm-mw-link-bracket { color: #219; font-weight: normal; }
|
||||
.cm-mw-link-text {}
|
||||
/* .cm-mw-link-text { } */
|
||||
.cm-mw-link-delimiter { color: #219; font-weight: normal; }
|
||||
|
||||
.cm-mw-extlink, .cm-mw-free-extlink { color: #219; font-weight: normal; }
|
||||
.cm-mw-extlink-protocol, .cm-mw-free-extlink-protocol { color: #219; font-weight: bold; }
|
||||
.cm-mw-extlink-text {}
|
||||
/* .cm-mw-extlink-text { } */
|
||||
.cm-mw-extlink-bracket { color: #219; font-weight: bold; }
|
||||
|
||||
.cm-mw-table-bracket { color: #e0e; font-weight: bold; }
|
||||
|
@ -75,7 +78,7 @@ pre.cm-mw-tag-nowiki, .cm-mw-tag-nowiki {background-image: url(img/black4.png);}
|
|||
.cm-mw-table-definition { color: #e0e; font-weight: normal; }
|
||||
.cm-mw-table-caption { font-weight: bold; }
|
||||
|
||||
.cm-mw-template-ground {}
|
||||
/* .cm-mw-template-ground {} */
|
||||
.cm-mw-template2-ground { background-image: url( img/template4.png ); }
|
||||
.cm-mw-template3-ground { background-image: url( img/template8.png ); }
|
||||
.cm-mw-template-ext-ground { background-image: url( img/ext4.png ); }
|
||||
|
@ -99,7 +102,7 @@ pre.cm-mw-tag-nowiki, .cm-mw-tag-nowiki {background-image: url(img/black4.png);}
|
|||
.cm-mw-template3-ext-link-ground { background-image: url( img/template8.png ), url( img/ext4.png ), url( img/link4.png ); }
|
||||
.cm-mw-template3-ext2-link-ground { background-image: url( img/template8.png ), url( img/ext4.png ), url( img/ext4.png ), url( img/link4.png ); }
|
||||
.cm-mw-template3-ext3-link-ground { background-image: url( img/template8.png ), url( img/ext4.png ), url( img/ext4.png ), url( img/ext4.png ), url( img/link4.png ); }
|
||||
.cm-mw-ext-ground {background-image: url(img/ext4.png)}
|
||||
.cm-mw-ext-ground { background-image: url( img/ext4.png ); }
|
||||
.cm-mw-ext2-ground { background-image: url( img/ext4.png ), url( img/ext4.png ); }
|
||||
.cm-mw-ext3-ground { background-image: url( img/ext4.png ), url( img/ext4.png ), url( img/ext4.png ); }
|
||||
.cm-mw-ext-link-ground { background-image: url( img/link4.png ); }
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable no-use-before-define */
|
||||
( function ( CodeMirror ) {
|
||||
'use strict';
|
||||
|
||||
|
@ -354,19 +355,20 @@
|
|||
function eatLinkText() {
|
||||
var linkIsBold, linkIsItalic;
|
||||
return function ( stream, state ) {
|
||||
var tmpstyle;
|
||||
if ( stream.match( ']]' ) ) {
|
||||
state.tokenize = state.stack.pop();
|
||||
return makeLocalStyle( 'mw-link-bracket', state, 'nLink' );
|
||||
}
|
||||
if ( stream.match( '\'\'\'' ) ) {
|
||||
linkIsBold = ( linkIsBold ? false : true );
|
||||
linkIsBold = !linkIsBold;
|
||||
return makeLocalStyle( 'mw-link-text mw-apostrophes', state );
|
||||
}
|
||||
if ( stream.match( '\'\'' ) ) {
|
||||
linkIsItalic = ( linkIsItalic ? false : true );
|
||||
linkIsItalic = !linkIsItalic;
|
||||
return makeLocalStyle( 'mw-link-text mw-apostrophes', state );
|
||||
}
|
||||
var tmpstyle = 'mw-link-text';
|
||||
tmpstyle = 'mw-link-text';
|
||||
if ( linkIsBold ) {
|
||||
tmpstyle += ' strong';
|
||||
}
|
||||
|
@ -627,13 +629,14 @@
|
|||
|
||||
function eatWikiText( style, mnemonicStyle ) {
|
||||
return function ( stream, state ) {
|
||||
var ch, tmp, mt, name, isCloseTag, tagname,
|
||||
sol = stream.sol();
|
||||
|
||||
function chain( parser ) {
|
||||
state.stack.push( state.tokenize );
|
||||
state.tokenize = parser;
|
||||
return parser( stream, state );
|
||||
}
|
||||
var ch,
|
||||
sol = stream.sol();
|
||||
|
||||
if ( sol ) {
|
||||
if ( stream.match( urlProtocols ) ) { // highlight free external links, bug T108448
|
||||
|
@ -649,7 +652,7 @@
|
|||
}
|
||||
break;
|
||||
case '=':
|
||||
var tmp = stream.match( /(={0,5})(.+?(=\1\s*))$/ );
|
||||
tmp = stream.match( /(={0,5})(.+?(=\1\s*))$/ );
|
||||
if ( tmp ) { // Title
|
||||
stream.backUp( tmp[ 2 ].length );
|
||||
state.stack.push( state.tokenize );
|
||||
|
@ -685,7 +688,7 @@
|
|||
return 'mw-skipformatting';
|
||||
}
|
||||
// break is not necessary here
|
||||
/*falls through*/
|
||||
// falls through
|
||||
case '{':
|
||||
if ( stream.eat( '|' ) ) {
|
||||
stream.eatSpace();
|
||||
|
@ -709,10 +712,10 @@
|
|||
if ( !( firstsingleletterword || stream.match( '\'\'', false ) ) ) {
|
||||
prepareItalicForCorrection( stream );
|
||||
}
|
||||
isBold = isBold ? false : true;
|
||||
isBold = !isBold;
|
||||
return makeLocalStyle( 'mw-apostrophes-bold', state );
|
||||
} else if ( stream.eat( '\'' ) ) { // italic
|
||||
isItalic = isItalic ? false : true;
|
||||
isItalic = !isItalic;
|
||||
return makeLocalStyle( 'mw-apostrophes-italic', state );
|
||||
}
|
||||
break;
|
||||
|
@ -726,7 +729,7 @@
|
|||
return makeLocalStyle( 'mw-link-bracket', state );
|
||||
}
|
||||
} else {
|
||||
var mt = stream.match( urlProtocols );
|
||||
mt = stream.match( urlProtocols );
|
||||
if ( mt ) {
|
||||
state.nLink++;
|
||||
stream.backUp( mt[ 0 ].length );
|
||||
|
@ -750,7 +753,7 @@
|
|||
return makeLocalStyle( 'mw-parserfunction-bracket', state );
|
||||
}
|
||||
// Check for parser function without '#'
|
||||
var name = stream.match( /([^\s\u00a0\}\[\]<\{\'\|\&\:]+)(\:|[\s\u00a0]*)(\}\}?)?(.)?/ );
|
||||
name = stream.match( /([^\s\u00a0\}\[\]<\{\'\|\&\:]+)(\:|[\s\u00a0]*)(\}\}?)?(.)?/ );
|
||||
if ( name ) {
|
||||
stream.backUp( name[ 0 ].length );
|
||||
if ( ( name[ 2 ] === ':' || name[ 4 ] === undefined || name[ 3 ] === '}}' ) && ( name[ 1 ].toLowerCase() in config.mwextFunctionSynonyms[ 0 ] || name[ 1 ] in config.mwextFunctionSynonyms[ 1 ] ) ) {
|
||||
|
@ -768,8 +771,8 @@
|
|||
}
|
||||
break;
|
||||
case '<':
|
||||
var isCloseTag = ( stream.eat( '/' ) ? true : false );
|
||||
var tagname = stream.match( /[^>\/\s\u00a0\.\*\,\[\]\{\}\$\^\+\?\|\/\\'`~<=!@#%&\(\)-]+/ );
|
||||
isCloseTag = !!stream.eat( '/' );
|
||||
tagname = stream.match( /[^>\/\s\u00a0\.\*\,\[\]\{\}\$\^\+\?\|\/\\'`~<=!@#%&\(\)-]+/ );
|
||||
if ( stream.match( '!--' ) ) { // coment
|
||||
return chain( eatBlock( 'mw-comment', '-->' ) );
|
||||
}
|
||||
|
@ -937,9 +940,10 @@
|
|||
return t.style;
|
||||
},
|
||||
blankLine: function ( state ) {
|
||||
var ret;
|
||||
if ( state.extName ) {
|
||||
if ( state.extMode ) {
|
||||
var ret = '';
|
||||
ret = '';
|
||||
if ( state.extMode.blankLine ) {
|
||||
ret = ' ' + state.extMode.blankLine( state.extState );
|
||||
}
|
||||
|
@ -955,12 +959,13 @@
|
|||
|
||||
function eatNowiki( style, lineStyle ) {
|
||||
return function ( stream, state, ownLine ) {
|
||||
var s;
|
||||
if ( ownLine && stream.sol() ) {
|
||||
state.ownLine = true;
|
||||
} else if ( ownLine === false && state.ownLine ) {
|
||||
state.ownLine = false;
|
||||
}
|
||||
var s = ( state.ownLine ? lineStyle : style );
|
||||
s = ( state.ownLine ? lineStyle : style );
|
||||
if ( stream.match( /[^&]+/ ) ) {
|
||||
return s;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue