Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
"core-js-url-browser": "3.6.4",
"csslint": "1.0.5",
"element-closest": "3.0.2",
"espree": "9.6.1",
"esprima": "4.0.1",
"formdata-polyfill": "4.0.10",
"hoverintent": "2.2.1",
Expand Down
109 changes: 109 additions & 0 deletions src/js/_enqueues/vendor/codemirror/javascript-lint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/* globals define, CodeMirror */

/* jshint esversion: 11 */

// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/LICENSE

// Depends on jshint.js from https://github.com/jshint/jshint

( function ( mod ) {
if ( typeof exports === 'object' && typeof module === 'object' ) {
// CommonJS
mod( require( 'codemirror' ) );
} else if ( typeof define === 'function' && define.amd ) {
// AMD
define( [ 'codemirror' ], mod );
// Plain browser env
} else {
mod( CodeMirror );
}
} )( function ( CodeMirror ) {
'use strict';

async function validator( text, options ) {
const espree = await import( 'espree' );

const errors = [];
try {
espree.parse( text, {
...getEspreeOptions( options ),
loc: true,
} );
} catch ( error ) {
// Note: A lineNumber of 0 causes CodeMirror to log out a warning in the console. This is as desired for a generic Espree error.

const line = error.lineNumber - 1;
const start = error.column - 1;
const end = error.column;

errors.push( {
message: error.message,
severity: 'error',
from: CodeMirror.Pos( line, start ),
to: CodeMirror.Pos( line, end ),
} );
}

return errors;
}

CodeMirror.registerHelper( 'lint', 'javascript', validator );

/**
* JSHint options supported by Espree.
*
* @see https://jshint.com/docs/options/
* @see https://www.npmjs.com/package/espree#options
*
* @typedef {Object} SupportedJSHintOptions
* @property {number} [esversion] - "This option is used to specify the ECMAScript version to which the code must adhere."
* @property {boolean} [es5] - "This option enables syntax first defined in the ECMAScript 5.1 specification. This includes allowing reserved keywords as object properties."
* @property {boolean} [es3] - "This option tells JSHint that your code needs to adhere to ECMAScript 3 specification. Use this option if you need your program to be executable in older browsers—such as Internet Explorer 6/7/8/9—and other legacy JavaScript environments."
* @property {boolean} [module] - "This option informs JSHint that the input code describes an ECMAScript 6 module. All module code is interpreted as strict mode code."
* @property {'implied'} [strict] - "This option requires the code to run in ECMAScript 5's strict mode."
*/

/**
* Gets the options for Espree from the supported JSHint options.
*
* @param {SupportedJSHintOptions} options - Linting options for JSHint.
* @return {{
* ecmaVersion?: number|'latest',
* ecmaFeatures?: {
* impliedStrict?: true
* }
* }}
*/
function getEspreeOptions( options ) {
const ecmaFeatures = {};
if ( options.strict === 'implied' ) {
ecmaFeatures.impliedStrict = true;
}

return {
ecmaVersion: getEcmaVersion( options ),
sourceType: options.module ? 'module' : 'script',
ecmaFeatures,
};
}

/**
* Gets the ECMAScript version.
*
* @param {SupportedJSHintOptions} options - Options.
* @return {number|'latest'} ECMAScript version.
*/
function getEcmaVersion( options ) {
if ( typeof options.esversion === 'number' ) {
return options.esversion;
}
if ( options.es5 ) {
return 5;
}
if ( options.es3 ) {
return 3;
}
return 'latest';
}
} );
56 changes: 30 additions & 26 deletions src/wp-includes/general-template.php
Original file line number Diff line number Diff line change
Expand Up @@ -4045,6 +4045,7 @@ function wp_enqueue_code_editor( $args ) {

wp_enqueue_script( 'code-editor' );
wp_enqueue_style( 'code-editor' );
wp_enqueue_script_module( 'wp-codemirror' ); // Hack to get importmap printed with espree.

if ( isset( $settings['codemirror']['mode'] ) ) {
$mode = $settings['codemirror']['mode'];
Expand All @@ -4069,7 +4070,6 @@ function wp_enqueue_code_editor( $args ) {
case 'text/x-php':
wp_enqueue_script( 'htmlhint' );
wp_enqueue_script( 'csslint' );
wp_enqueue_script( 'jshint' );
if ( ! current_user_can( 'unfiltered_html' ) ) {
wp_enqueue_script( 'htmlhint-kses' );
}
Expand All @@ -4081,7 +4081,6 @@ function wp_enqueue_code_editor( $args ) {
case 'application/ld+json':
case 'text/typescript':
case 'application/typescript':
wp_enqueue_script( 'jshint' );
wp_enqueue_script( 'jsonlint' );
break;
}
Expand Down Expand Up @@ -4153,30 +4152,35 @@ function wp_get_code_editor_settings( $args ) {
'outline-none' => true,
),
'jshint' => array(
// The following are copied from <https://github.com/WordPress/wordpress-develop/blob/4.8.1/.jshintrc>.
'boss' => true,
'curly' => true,
'eqeqeq' => true,
'eqnull' => true,
'es3' => true,
'expr' => true,
'immed' => true,
'noarg' => true,
'nonbsp' => true,
'onevar' => true,
'quotmark' => 'single',
'trailing' => true,
'undef' => true,
'unused' => true,

'browser' => true,

'globals' => array(
'_' => false,
'Backbone' => false,
'jQuery' => false,
'JSON' => false,
'wp' => false,
// This version is copied from <https://github.com/WordPress/wordpress-develop/blob/6.9.0/.jshintrc>.
'esversion' => 10,

// The remaining options are not supported by Espree, which is used instead of JSHint for licensing reasons.
'boss' => true,
'curly' => true,
'eqeqeq' => true,
'eqnull' => true,
'expr' => true,
'immed' => true,
'noarg' => true,
'nonbsp' => true,
'quotmark' => 'single',
'undef' => true,
'unused' => true,
'browser' => true,
'globals' => array(
'_' => false,
'Backbone' => false,
'jQuery' => false,
'JSON' => false,
'wp' => false,
'export' => false,
'module' => false,
'require' => false,
'WorkerGlobalScope' => false,
'self' => false,
'OffscreenCanvas' => false,
'Promise' => false,
),
),
'htmlhint' => array(
Expand Down
4 changes: 2 additions & 2 deletions src/wp-includes/script-loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -1197,8 +1197,8 @@ function wp_default_scripts( $scripts ) {

$scripts->add( 'wp-codemirror', '/wp-includes/js/codemirror/codemirror.min.js', array(), '5.65.20' );
$scripts->add( 'csslint', '/wp-includes/js/codemirror/csslint.js', array(), '1.0.5' );
$scripts->add( 'esprima', '/wp-includes/js/codemirror/esprima.js', array(), '4.0.1' );
$scripts->add( 'jshint', '/wp-includes/js/codemirror/fakejshint.js', array( 'esprima' ), '2.9.5' );
$scripts->add( 'esprima', '/wp-includes/js/codemirror/esprima.js', array(), '4.0.1' ); // Deprecated. Use 'espree' script module.
$scripts->add( 'jshint', '/wp-includes/js/codemirror/fakejshint.js', array( 'esprima' ), '2.9.5' ); // Deprecated.
$scripts->add( 'jsonlint', '/wp-includes/js/codemirror/jsonlint.js', array(), '1.6.3' );
$scripts->add( 'htmlhint', '/wp-includes/js/codemirror/htmlhint.js', array(), '1.8.0' );
$scripts->add( 'htmlhint-kses', '/wp-includes/js/codemirror/htmlhint-kses.js', array( 'htmlhint' ) );
Expand Down
19 changes: 19 additions & 0 deletions src/wp-includes/script-modules.php
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,25 @@ function wp_default_script_modules() {
$module_deps = $script_module_data['module_dependencies'] ?? array();
wp_register_script_module( $script_module_id, $path, $module_deps, $script_module_data['version'], $args );
}

wp_register_script_module(
'espree',
includes_url( 'js/codemirror/espree.min.js' ),
array(),
'9.6.1'
);

// The following is a workaround for classic scripts not yet being able to depend on modules. See <https://core.trac.wordpress.org/ticket/61500>.
wp_register_script_module(
'wp-codemirror',
'', // An empty string is a hack to cause the dependencies to be printed in the importmap without a dependent script being printed.
array(
array(
'id' => 'espree',
'import' => 'dynamic',
),
)
);
}

/**
Expand Down
18 changes: 5 additions & 13 deletions tests/phpunit/tests/dependencies/scripts.php
Original file line number Diff line number Diff line change
Expand Up @@ -3039,14 +3039,12 @@ public function test_wp_enqueue_code_editor_when_php_file_will_be_passed() {
'curly',
'eqeqeq',
'eqnull',
'es3',
'esversion',
'expr',
'immed',
'noarg',
'nonbsp',
'onevar',
'quotmark',
'trailing',
'undef',
'unused',
'browser',
Expand Down Expand Up @@ -3123,14 +3121,12 @@ public function test_wp_enqueue_code_editor_when_generated_array_by_compact_will
'curly',
'eqeqeq',
'eqnull',
'es3',
'esversion',
'expr',
'immed',
'noarg',
'nonbsp',
'onevar',
'quotmark',
'trailing',
'undef',
'unused',
'browser',
Expand Down Expand Up @@ -3221,14 +3217,12 @@ public function test_wp_enqueue_code_editor_when_generated_array_by_array_merge_
'curly',
'eqeqeq',
'eqnull',
'es3',
'esversion',
'expr',
'immed',
'noarg',
'nonbsp',
'onevar',
'quotmark',
'trailing',
'undef',
'unused',
'browser',
Expand Down Expand Up @@ -3316,14 +3310,12 @@ public function test_wp_enqueue_code_editor_when_simple_array_will_be_passed() {
'curly',
'eqeqeq',
'eqnull',
'es3',
'esversion',
'expr',
'immed',
'noarg',
'nonbsp',
'onevar',
'quotmark',
'trailing',
'undef',
'unused',
'browser',
Expand Down Expand Up @@ -3901,7 +3893,7 @@ static function ( $dependency ) {
);

// Exclude packages that are not registered in WordPress.
$exclude = array( 'react-is', 'json2php' );
$exclude = array( 'react-is', 'json2php', 'espree' );
$package_json_dependencies = array_diff( $package_json_dependencies, $exclude );

/*
Expand Down
3 changes: 2 additions & 1 deletion tools/vendors/codemirror-entry.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ require( 'codemirror/addon/hint/xml-hint' );
require( 'codemirror/addon/lint/lint' );
require( 'codemirror/addon/lint/css-lint' );
require( 'codemirror/addon/lint/html-lint' );
require( 'codemirror/addon/lint/javascript-lint' );

require( '../../src/js/_enqueues/vendor/codemirror/javascript-lint' );
require( 'codemirror/addon/lint/json-lint' );

// Addons (Other)
Expand Down
1 change: 1 addition & 0 deletions tools/vendors/espree-entry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from 'espree';
Loading