Skip to content

Conversation

@westonruter
Copy link
Member

@westonruter westonruter commented Jan 23, 2026

Trac ticket: https://core.trac.wordpress.org/ticket/48456

For Gemini CLI, I provided the following spec:

From commit dbace68 you can see that CodeMirror was originally introduced. In a91d398 it was integrated into the Customizer. Note also in 5bb7fc1 that JSHint was removed due to license compatibility. This was many years ago. The version of CodeMirror installed then was 5.29.1-alpha-ee20357. However, the latest version of CodeMirror v5 is 5.65.18 as seen at https://github.com/codemirror/codemirror5/releases. Granted, there is now a complete rewrite in CodeMirror v6, but before we upgrade to v6 we should first upgrade to the latest v5, as requested in https://core.trac.wordpress.org/ticket/48456. Part of the reason why we didn't upgrade previously is that there was no script to facilitate upgrading.

I want you to come up with a plan for how we might upgrade to the latest version of CodeMirror v5, taking into account all of the release notes for all versions of CodeMirror since 5.29.1, or rather, since 5.29.0 https://github.com/codemirror/codemirror5/releases/tag/5.29.0. I don't actually see that 5.29.1 was ever released since the actual release that included commit codemirror/codemirror5@ee20357 was 5.30.0. In any case, I need a plan to upgrade CodeMirror which is currently located in @src/js/_enqueues/vendor/codemirror/ (where initially it was located at @src/wp-includes/js/codemirror but with ef37f00 there was a build step introduced which caused files to be moved around).

So I need a plan for:

  1. A new Grunt task like codemirror:update which will handle pulling down the latest version of CodeMirror v5 and to update the versions for wp-codemirror script/style in @src/wp-includes/script-loader.php as well as the other script handles in that directory, specifically the add-ons for jshint, jsonlint, htmlhint, csslint. The jshint add-on was replaced in 5bb7fc1 with esprima, so that is out of scope for updating.
  2. Updating dependencies of the wp-codemirror script to account for any back-compat breakages. Note that the code-editor script/style is the main dependency. Take care to note how the code-editor dependency is used, namely in the wp-theme-plugin-editor script, the wp_enqueue_code_editor() function where the script gets enqueued. The wp_enqueue_code_editor() function is used in @src/wp-includes/widgets/class-wp-widget-custom-html.php and src/wp-includes/customize/class-wp-customize-code-editor-control.php as well as in @src/wp-admin/theme-editor.php and @src/wp-admin/plugin-editor.php.

You will not make any changes to the codebase for now. Only come up with a plan. Remember that backwards compatibility is paramount in WordPress, so take care to consider how existing ecosystem code may be extending CodeMirror in 5.29.1-alpha-ee20357 which has been present in core for 9 years.

I also provided https://github.com/WordPress/better-code-editing as context for where the CodeMirror integration originally came from.

I then iterated on the plan with Gemini for awhile, and came up with the following:

Plan for Upgrading CodeMirror to v5.65.18

This plan upgrades CodeMirror to version 5.65.18 by transitioning from a manually bundled artifact to a build-generated asset sourced from npm. It mirrors the integration strategy of the better-code-editing plugin (the feature's origin) while adapting to the modern wordpress-develop build system (Webpack) and updating dependencies to their latest compatible versions.

1. Dependency Management [COMPLETED]

Add codemirror and required linters to package.json dependencies. We are updating these to the latest versions compatible with CodeMirror 5, rather than using the outdated versions from the original plugin.

  • Action: Update package.json dependencies with:
    • "codemirror": "5.65.18"
    • "csslint": "1.0.5"
    • "htmlhint": "1.1.4"
    • "jsonlint": "1.6.3"
    • "esprima": "4.0.1"
  • Note: jshint is excluded because Core uses a custom fakejshint.js wrapper (powered by esprima) instead of the standard library.

2. Source File Cleanup [COMPLETED]

Remove the pre-bundled CodeMirror files and standalone linters from the source tree, as they will be replaced by build artifacts.

  • Action: Delete from src/js/_enqueues/vendor/codemirror/:
    • codemirror.min.js
    • codemirror.min.css
    • csslint.js
    • esprima.js
    • htmlhint.js
    • jsonlint.js
  • Keep: fakejshint.js and htmlhint-kses.js (Core-specific wrappers).

3. Build Tooling Implementation [COMPLETED]

3.1. Webpack Entry Point (tools/vendors/codemirror-entry.js)

Create an entry point that replicates the original codemirror.manifest.js. This file aggregates the core library, modes, keymaps, and addons into a single bundle and exposes the global object.

  • Content:
    // Define CodeMirror globally before other imports to ensure they attach to it.
    var CodeMirror = require( 'codemirror/lib/codemirror' );
    
    // Keymaps
    require( 'codemirror/keymap/emacs' );
    require( 'codemirror/keymap/sublime' );
    require( 'codemirror/keymap/vim' );
    
    // Addons (Hinting)
    require( 'codemirror/addon/hint/show-hint' );
    require( 'codemirror/addon/hint/anyword-hint' );
    require( 'codemirror/addon/hint/css-hint' );
    require( 'codemirror/addon/hint/html-hint' );
    require( 'codemirror/addon/hint/javascript-hint' );
    require( 'codemirror/addon/hint/sql-hint' );
    require( 'codemirror/addon/hint/xml-hint' );
    
    // Addons (Linting)
    require( 'codemirror/addon/lint/lint' );
    require( 'codemirror/addon/lint/css-lint' );
    require( 'codemirror/addon/lint/html-lint' );
    require( 'codemirror/addon/lint/javascript-lint' );
    require( 'codemirror/addon/lint/json-lint' );
    
    // Addons (Other)
    require( 'codemirror/addon/comment/comment' );
    require( 'codemirror/addon/comment/continuecomment' );
    require( 'codemirror/addon/fold/xml-fold' );
    require( 'codemirror/addon/mode/overlay' );
    require( 'codemirror/addon/edit/closebrackets' );
    require( 'codemirror/addon/edit/closetag' );
    require( 'codemirror/addon/edit/continuelist' );
    require( 'codemirror/addon/edit/matchbrackets' );
    require( 'codemirror/addon/edit/matchtags' );
    require( 'codemirror/addon/edit/trailingspace' );
    require( 'codemirror/addon/dialog/dialog' );
    require( 'codemirror/addon/display/autorefresh' );
    require( 'codemirror/addon/display/fullscreen' );
    require( 'codemirror/addon/display/panel' );
    require( 'codemirror/addon/display/placeholder' );
    require( 'codemirror/addon/display/rulers' );
    require( 'codemirror/addon/fold/brace-fold' );
    require( 'codemirror/addon/fold/comment-fold' );
    require( 'codemirror/addon/fold/foldcode' );
    require( 'codemirror/addon/fold/foldgutter' );
    require( 'codemirror/addon/fold/indent-fold' );
    require( 'codemirror/addon/fold/markdown-fold' );
    require( 'codemirror/addon/merge/merge' );
    require( 'codemirror/addon/mode/loadmode' );
    require( 'codemirror/addon/mode/multiplex' );
    require( 'codemirror/addon/mode/simple' );
    require( 'codemirror/addon/runmode/runmode' );
    require( 'codemirror/addon/runmode/colorize' );
    require( 'codemirror/addon/runmode/runmode-standalone' );
    require( 'codemirror/addon/scroll/annotatescrollbar' );
    require( 'codemirror/addon/scroll/scrollpastend' );
    require( 'codemirror/addon/scroll/simplescrollbars' );
    require( 'codemirror/addon/search/search' );
    require( 'codemirror/addon/search/jump-to-line' );
    require( 'codemirror/addon/search/match-highlighter' );
    require( 'codemirror/addon/search/matchesonscrollbar' );
    require( 'codemirror/addon/search/searchcursor' );
    require( 'codemirror/addon/tern/tern' );
    require( 'codemirror/addon/tern/worker' );
    require( 'codemirror/addon/wrap/hardwrap' );
    require( 'codemirror/addon/selection/active-line' );
    require( 'codemirror/addon/selection/mark-selection' );
    require( 'codemirror/addon/selection/selection-pointer' );
    
    // Modes
    require( 'codemirror/mode/meta' );
    require( 'codemirror/mode/clike/clike' );
    require( 'codemirror/mode/css/css' );
    require( 'codemirror/mode/diff/diff' );
    require( 'codemirror/mode/htmlmixed/htmlmixed' );
    require( 'codemirror/mode/http/http' );
    require( 'codemirror/mode/javascript/javascript' );
    require( 'codemirror/mode/jsx/jsx' );
    require( 'codemirror/mode/markdown/markdown' );
    require( 'codemirror/mode/gfm/gfm' );
    require( 'codemirror/mode/nginx/nginx' );
    require( 'codemirror/mode/php/php' );
    require( 'codemirror/mode/sass/sass' );
    require( 'codemirror/mode/shell/shell' );
    require( 'codemirror/mode/sql/sql' );
    require( 'codemirror/mode/xml/xml' );
    require( 'codemirror/mode/yaml/yaml' );
    
    // Global Exposure
    if ( ! window.wp ) {
        window.wp = {};
    }
    window.wp.CodeMirror = CodeMirror;

3.2. Webpack Configuration [COMPLETED]

Create tools/webpack/codemirror.config.js to handle the JS bundling.

  • Input: tools/vendors/codemirror-entry.js
  • Output: src/wp-includes/js/codemirror/codemirror.min.js

3.3. Grunt Configuration (Gruntfile.js) [COMPLETED]

Update Gruntfile.js to manage the full build process for CodeMirror assets.

  1. Webpack Task: Added a codemirror target pointing to the new config.
  2. CSS Concatenation: Added a concat:codemirror target to bundle styles into codemirror.css:
    • node_modules/codemirror/lib/codemirror.css
    • node_modules/codemirror/addon/hint/show-hint.css
    • node_modules/codemirror/addon/lint/lint.css
    • node_modules/codemirror/addon/dialog/dialog.css
    • node_modules/codemirror/addon/display/fullscreen.css
    • node_modules/codemirror/addon/fold/foldgutter.css
    • node_modules/codemirror/addon/merge/merge.css
    • node_modules/codemirror/addon/scroll/simplescrollbars.css
    • node_modules/codemirror/addon/search/matchesonscrollbar.css
    • node_modules/codemirror/addon/tern/tern.css
  3. CSS Minification: Added a cssmin:codemirror target.
  4. Copy Task: Added a copy:codemirror target to copy linters and preserve custom wrappers.
  5. Build Integration: Added build:codemirror to the main build task.

IMPORTANT: Build artifacts generated in src/wp-includes/js/codemirror/ are ignored by Git (via the /src/wp-includes/js rule in .gitignore). These files must NOT be staged or committed.

4. Script Loader Update (src/wp-includes/script-loader.php) [COMPLETED]

Update the registered versions for the following handles to match the new packages:

  • wp-codemirror (v5.65.18)
  • csslint (v1.0.5)
  • htmlhint (v1.1.4)
  • jsonlint (v1.6.3)
  • esprima (v4.0.1)

5. Verification [COMPLETED]

  1. Build: Run grunt build:codemirror --dev and verify existence of:
    • src/wp-includes/js/codemirror/codemirror.min.js
    • src/wp-includes/js/codemirror/codemirror.min.css
    • Linter files in the same directory.
  2. Runtime: Check window.CodeMirror.version and window.wp.CodeMirror in the browser console.
  3. Functionality:
    • Test Theme Editor (syntax highlighting, line numbers).
    • Test Custom CSS (linting warnings).
    • Test Custom HTML Widget.

I then told Gemini to execute the plan, creating commits for each logical step.

Initial Gemini Review

The changes look solid and represent a significant improvement in how CodeMirror is managed in WordPress Core, moving from committed artifacts to a proper build process backed by npm dependencies.

I have a few items for you to address:

  1. License Header in JS Bundle: The previous codemirror.min.js included a comment block with license information. Your new Webpack config (tools/webpack/codemirror.config.js) uses TerserPlugin with extractComments: false and comments: false, which strips all comments.
    • Action: Please configure TerserPlugin to preserve @license or @preserve comments, or use webpack.BannerPlugin to prepend the CodeMirror license information to the generated codemirror.min.js.

Addressed in 2fb47e4, 3fb2281, 79295b3

  1. CSS Source Mapping/Banner: In Gruntfile.js, you added a process function to concat:codemirror:
    process: function( src, filepath ) {
        return '/* Source: ' + filepath.replace( 'node_modules/', '' ) + '*/\n' + src;
    }
    This adds comments to the concatenated CSS file (codemirror.css), but the cssmin:codemirror task will likely strip these comments when generating codemirror.min.css.
    • Action: Verify if these source comments are intended to remain in the minified file. If not, this is fine for the unminified version, but ensure the license is preserved here as well if required.

Removed in 0dcbf28.

  1. Completeness of Addons: The list of requires in tools/vendors/codemirror-entry.js is extensive.
    • Observation: Please double-check that this list matches the functionality provided by the previous 5.29.1 bundle. Specifically, ensure no used modes or addons (like match-highlighter or specific keymaps) were accidentally omitted if they were previously present.

Yes, they match the original manifest: https://github.com/WordPress/better-code-editing/blob/master/wp-includes/js/codemirror/codemirror.manifest.js

Gemini also pointed out an issue where the core library was being included twice before. Now it is included once. This doesn't appear to have any impact on the resulting bundle size, however.

The new codemirror.min.js is 620,848 bytes. The old one was 585,414 bytes. So the newer version of CodeMirror is a bit larger.

  1. fakejshint.js and htmlhint-kses.js Location:
    • You are copying these from SOURCE_DIR + 'js/_enqueues/vendor/codemirror/' to WORKING_DIR + 'wp-includes/js/codemirror/'.
    • Observation: Since these are Core-specific wrappers and not external vendor code (strictly speaking), ensure they are tracked correctly in git. The delete command removed the other files in that directory, leaving these two. This seems correct, but just confirming their source location is intended to stay in vendor.

Yes. That is correct.

  1. Script Loader Versions:
    • In src/wp-includes/script-loader.php, you updated the versions.
    • Nit: jshint is still listed as 2.9.5. Since it relies on esprima (which you updated to 4.0.1) and fakejshint.js, verify if fakejshint.js needs any updates to work with the newer esprima version.

Since fakehshint.js is unchanged, it doesn't seem like it should have its version updated, even though it was swapped out originally in 5bb7fc1 without having its version changed (which it should have to bust caches).

Overall, excellent work modernizing this dependency chain. Fix the license header issue, and it should be ready.

Second Gemini Review

I have reviewed the changes. The upgrade to CodeMirror 5.65.20 and the shift to npm/webpack management look solid.

I have a few observations and one question regarding the unminified sources for SCRIPT_DEBUG.

1. HTMLHint Source

In Gruntfile.js, the copy:codemirror task copies the minified version of HTMLHint to a file named htmlhint.js:

[ WORKING_DIR + 'wp-includes/js/codemirror/htmlhint.js' ]: [ './node_modules/htmlhint/dist/htmlhint.min.js' ],

The file being deleted (src/js/_enqueues/vendor/codemirror/htmlhint.js) appeared to be unminified (or at least lacked the .min suffix). If node_modules/htmlhint/dist/htmlhint.js exists, it would be preferable to copy that instead. This ensures that when SCRIPT_DEBUG is enabled, developers get the readable source. If the file needs to be minified for production, we should probably add a uglify or terser task for it, or copy the .min.js version to htmlhint.min.js specifically.

Currently, script-loader.php registers it as:

$scripts->add( 'htmlhint', '/wp-includes/js/codemirror/htmlhint.js', array(), '1.8.0' );

WordPress will auto-suffix .min in production. If htmlhint.js contains minified code, then SCRIPT_DEBUG users will still see minified code, which isn't ideal.

The file was actually minified: https://github.com/WordPress/wordpress-develop/blob/trunk/src/js/_enqueues/vendor/codemirror/htmlhint.js

So this is consistent.

2. CodeMirror Build Artifacts

The tools/webpack/codemirror.config.js is configured to output only codemirror.min.js:

output: {
    path: path.resolve( __dirname, '../../src/wp-includes/js/codemirror' ),
    filename: 'codemirror.min.js',
},
optimization: {
    minimize: true,
    // ...
}

And script-loader.php points to it:

$scripts->add( 'wp-codemirror', '/wp-includes/js/codemirror/codemirror.min.js', array(), '5.65.20' );

While the previous version also pointed to codemirror.min.js, it's worth considering if we should generate an unminified codemirror.js bundle as well for debugging purposes. However, since the previous version didn't seem to have one in the repo (based on the deletions), this preserves the status quo.

Keeping only the minified versions preserves the status quo, and keeps the ZIP from growing.

3. JSHint / fakejshint

The patch for htmlhint in Gruntfile.js handles the global namespace issue nicely.
I noticed fakejshint.js is still being copied from source:

cwd: SOURCE_DIR + 'js/_enqueues/vendor/codemirror/',
src: [ 'fakejshint.js', 'htmlhint-kses.js' ],

This is correct as these are Core-specific wrappers.

4. package.json Sorting

The reordering of @pmmmwh/react-refresh-webpack-plugin is just alphabetical sorting, which is fine.

Summary

The changes are technically sound and follow the modern build process of the repository. My only "nit" is regarding the htmlhint.js source file being minified code.

Verdict:
Review APPROVED (with suggestion to use unminified source for htmlhint.js if possible).

Demos

PHP file in Plugin Editor

Screen.Recording.2026-01-22.at.21.57.10.mov

JS file in Theme Editor

Screen.Recording.2026-01-22.at.22.09.17.mov

CSS file in Theme Editor

Screen.Recording.2026-01-22.at.22.10.33.mov

Additional CSS in Customizer

Screen.Recording.2026-01-22.at.22.11.47.mov

Custom HTML Widget with disallowed unfiltered_html

Screen.Recording.2026-01-22.at.22.14.07.mov

This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.

westonruter and others added 9 commits January 22, 2026 17:24
Adds codemirror, csslint, htmlhint, jsonlint, and esprima to package.json dependencies to manage them via npm. This aligns with the strategy for other vendor libraries in Core.

Command: npm install codemirror@5.65.18 csslint@1.0.5 htmlhint@1.1.4 jsonlint@1.6.3 esprima@4.0.1 --save-prod --save-exact

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Removes manually bundled codemirror.min.js/css and standalone linters (csslint, esprima, htmlhint, jsonlint) from src/js/_enqueues/vendor/codemirror/. These will be replaced by artifacts generated from npm dependencies via the build process.

Core-specific wrappers (fakejshint.js, htmlhint-kses.js) are preserved.

Command: rm src/js/_enqueues/vendor/codemirror/codemirror.min.js src/js/_enqueues/vendor/codemirror/codemirror.min.css src/js/_enqueues/vendor/codemirror/csslint.js src/js/_enqueues/vendor/codemirror/esprima.js src/js/_enqueues/vendor/codemirror/htmlhint.js src/js/_enqueues/vendor/codemirror/jsonlint.js

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Creates tools/vendors/codemirror-entry.js, which replicates the logic of the original codemirror.manifest.js. This file aggregates the core library, modes, keymaps, and addons into a single entry point for the build process and exposes the global window.wp.CodeMirror object.

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Adds tools/webpack/codemirror.config.js to handle the bundling of the CodeMirror entry point into src/wp-includes/js/codemirror/codemirror.min.js.

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Updates Gruntfile.js to include tasks for building CodeMirror:
- Registers a 'codemirror' target for webpack to bundle the JS.
- Registers a 'codemirror' target for concat to bundle the CSS.
- Registers a 'codemirror' target for cssmin to minify the CSS.
- Registers a 'codemirror' target for copy to move linters and wrappers.
- Creates a combined 'build:codemirror' task.
- Adds 'build:codemirror' to the main 'build' task workflow.

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Updates the version strings for CodeMirror and its related linters (csslint, esprima, jsonlint, htmlhint) to reflect the upgrade to v5.65.18.

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Adds the required license header to the minified CodeMirror bundles during the build process.

- Updates tools/webpack/codemirror.config.js to include the license header using BannerPlugin and ensures Terser preserves important comments.
- Adds a usebanner:codemirror task to Gruntfile.js to append the license header to the minified CSS.
- Dynamically retrieves the CodeMirror version from package.json for inclusion in the header.
- Reformats the license headers to use multi-line backtick string literals for better maintainability.

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Ensures the CodeMirror license banner is applied to the unminified `codemirror.css` file in addition to the minified version. Also enables the `linebreak` option for the CodeMirror banner to ensure a newline separates the header from the content.

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Refactors the CodeMirror CSS build process to add the license banner to the unminified `codemirror.css` file first. The `cssmin` task then generates `codemirror.min.css` from this file, preserving the license header while stripping unnecessary whitespace.

- Updates `usebanner:codemirror` to target only the unminified file.
- Reorders the `build:codemirror` task sequence to run `usebanner:codemirror` before `cssmin:codemirror`.

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@github-actions
Copy link

Test using WordPress Playground

The changes in this pull request can previewed and tested using a WordPress Playground instance.

WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Some things to be aware of

  • The Plugin and Theme Directories cannot be accessed within Playground.
  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

westonruter and others added 3 commits January 22, 2026 19:04
Updates the CodeMirror CSS build process to perform concatenation and minification in a single `cssmin` task. This eliminates the need for an intermediate unminified file and ensures the license banner is applied correctly to the final minified bundle without an extra newline.

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Adds `codemirror`, `csslint`, `esprima`, `htmlhint`, and `jsonlint` to the manually registered vendor scripts data provider in `Tests_Dependencies_Scripts::data_vendor_script_versions_registered_manually`. This ensures that `test_vendor_script_data_provider_includes_all_packages` passes by accounting for these dependencies which are present in `package.json`.

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
westonruter and others added 4 commits January 22, 2026 21:20
Upgrades `htmlhint` to v1.8.0 and configures it as an external in the CodeMirror Webpack bundle to avoid duplicate code and ensure compatibility with Core wrappers.

- Handles the change in HTMLHint's UMD export structure (where the instance is nested under `HTMLHint.HTMLHint`) by applying a build-time patch to `htmlhint.js` during the copy task. This patch unwraps the instance into the global scope, ensuring compatibility with CodeMirror's `html-lint` addon and WordPress's `htmlhint-kses` wrapper.
- Configures `tools/webpack/codemirror.config.js` to use `window.*` for linter externals (`htmlhint`, `csslint`, `jshint`, `jsonlint`), preventing `ReferenceError` when these optional libraries are not loaded.
- Updates `package.json` and `script-loader.php` to reflect the HTMLHint v1.8.0 upgrade.

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Updates the `copy:codemirror` task in `Gruntfile.js` to correctly identify and patch `htmlhint.min.js`. This ensures that the `HTMLHint` global is correctly unwrapped (fixing the namespace issue) when using the minified distribution of HTMLHint v1.8.0.

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Upgrades `codemirror` from 5.65.18 to 5.65.20 in `package.json` and `script-loader.php`. This ensures WordPress is using the absolute latest maintenance release of the CodeMirror v5 series.

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@westonruter westonruter marked this pull request as ready for review January 23, 2026 05:45
@github-actions
Copy link

github-actions bot commented Jan 23, 2026

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props westonruter, tobiasbg.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

Aligns the JSHint settings used in the code editor with the project's `.jshintrc` file. This includes updating to ES10, removing deprecated options like `es3`, `onevar`, and `trailing`, and adding missing globals.

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR upgrades WordPress Core’s CodeMirror v5 integration to a newer upstream release by sourcing CodeMirror (and related linters) from npm and generating the runtime assets via the build tooling, then updating registered script/style versions accordingly.

Changes:

  • Add npm dependencies for codemirror and linters (csslint, htmlhint, jsonlint, esprima), and update vendor version assertions in PHPUnit.
  • Introduce a dedicated Webpack entry/config to bundle CodeMirror + addons/modes, and wire a new build:codemirror task into the main Grunt build.
  • Update wp_default_scripts() / wp_default_styles() registrations to the new package versions.

Reviewed changes

Copilot reviewed 6 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tools/webpack/codemirror.config.js New Webpack config for building codemirror.min.js with a license banner and externals for linters.
tools/vendors/codemirror-entry.js New Webpack entry that imports CodeMirror core + required addons/modes and exposes it on window.wp.
Gruntfile.js Adds webpack:codemirror, cssmin:codemirror, copy:codemirror, banner handling, and integrates build:codemirror into build.
src/wp-includes/script-loader.php Updates registered versions for wp-codemirror and linter handles to match npm package versions.
tests/phpunit/tests/dependencies/scripts.php Extends vendor-version test coverage to include CodeMirror and linter handles.
package.json / package-lock.json Adds/locks new npm dependencies required for the CodeMirror + linter build pipeline.
src/js/_enqueues/vendor/codemirror/* Removes previously bundled vendor artifacts now sourced from npm/build (leaving core wrappers).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

westonruter and others added 3 commits January 22, 2026 22:21
Updates `tools/webpack/codemirror.config.js` to export a function that accepts a `buildTarget` parameter, ensuring the bundled CodeMirror script is written to the correct directory (`src/` for dev builds, `build/` for production). Also updates `Gruntfile.js` to pass the `WORKING_DIR` to this configuration function.

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Updates the comments in `codemirror-entry.js` to correctly describe the CodeMirror import and explain the distinction between `window.wp.CodeMirror` and the minimal version set by the `runmode-standalone` addon.

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Resets the global `usebanner.options.linebreak` to `true` to prevent affecting other build outputs, while maintaining `linebreak: false` specifically for the CodeMirror CSS bundle.

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
'curly' => true,
'eqeqeq' => true,
'eqnull' => true,
'esversion' => 10,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that esprima doesn't support this, apparently, so ES6 syntax still is reported as a syntax error 😦

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See https://esprima.org/doc/es6.html

Given that Esprima hasn't been updated in 8 years, we might want to consider turning JS linting off by default the same as we did for CSS.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See Core-44471 for why CSS linting was disabled for a similar reason.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like we could replace Esprima with Espree which is actively maintained: https://www.npmjs.com/package/espree

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hah. So easy: ee2b6bd

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want to revert this commit for another ticket, but it's closely related and I think makes sense to go out together.

@westonruter westonruter requested a review from sirreal January 23, 2026 07:00
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 14 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +4156 to +4162
// The following are copied from <https://github.com/WordPress/wordpress-develop/blob/6.9.0/.jshintrc>.
'boss' => true,
'curly' => true,
'eqeqeq' => true,
'eqnull' => true,
'esversion' => 10,
'expr' => true,
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JSHint defaults are now kept in sync with the repo’s root .jshintrc (which is great), but the comment references a specific GitHub URL/tag. To reduce churn/broken links over time, consider referencing the local .jshintrc file (or a relative path) instead of a versioned external URL.

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really relevant here. It would be nice to not duplicate but in reality this file changes very rarely.

westonruter and others added 4 commits January 22, 2026 23:50
Moves the CodeMirror license banner to a dedicated `codemirror-banner.js` file to avoid duplication between the Grunt and Webpack configurations and ensure consistency across JS and CSS build outputs.

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…ions.

Sets `target: 'browserslist'` and provides a default for the `env` parameter in `codemirror.config.js` to ensure consistent browser compatibility and prevent runtime errors when called without arguments.

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Replaces the outdated `esprima` parser with `espree` to provide support for modern JavaScript (ES6+) validation in the code editor. A new `espree` script handle is registered, and the `fakejshint` wrapper is updated to use it while maintaining the `esprima` handle for backward compatibility.

- Adds `espree` to `package.json`.
- Creates `tools/vendors/espree-entry.js` and adds a new Webpack entry point to bundle `espree`.
- Updates `fakejshint.js` to utilize `window.espree.parse` with ES6+ support.
- Registers `espree` in `script-loader.php` and updates `jshint` handle dependencies.
- Updates PHPUnit test data provider to include `espree`.

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@TobiasBg
Copy link

I tested this PR in Playground, by installing my plugin (TablePress), which embeds CodeMirror on its "Plugin Options" screen, for adding CSS code.
Everything worked fine with the new version, no issues :-)

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 17 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +185 to +187
src: [
WORKING_DIR + 'wp-includes/js/codemirror/codemirror.min.css'
]
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

usebanner is invoked without a target as part of build:css (see the build:css task later in this file). Adding a separate usebanner:codemirror target means grunt usebanner will also try to banner wp-includes/js/codemirror/codemirror.min.css during build:css, but that file is only generated in build:codemirror (which runs afterwards). Consider changing build:css to run usebanner:files (and keep usebanner:codemirror only in build:codemirror), or otherwise reordering tasks so the file exists when the usebanner:codemirror target runs.

Suggested change
src: [
WORKING_DIR + 'wp-includes/js/codemirror/codemirror.min.css'
]
src: []

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in cf742fa.

Gemini's reasoning:

The problem solved is a task execution conflict that would occur during a full production build (grunt build).

In Grunt, if you invoke a task without a specific target (e.g., calling 'usebanner' instead of 'usebanner:files'), it automatically tries to run all defined targets for that task.

In your Gruntfile.js, usebanner has two targets:

  1. files: Handles general WordPress Core CSS/JS.
  2. codemirror: Handles the specific CodeMirror CSS bundle.

The build:css task (which is part of the main Core build) was calling the generic 'usebanner'. This meant that every time someone ran a standard CSS build, Grunt would try to add a banner to wp-includes/js/codemirror/codemirror.min.css.

However, that CodeMirror file is not created until the build:codemirror task runs later. This would cause Grunt to throw a "File not found" warning or error during the general CSS build phase.

By explicitly calling 'usebanner:files' in build:css, we ensure that the general build only touches general files, and the CodeMirror banner is handled only when CodeMirror itself is actually being built.

westonruter and others added 4 commits January 23, 2026 08:36
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Updates `build:css` to specifically invoke `usebanner:files` and `build:codemirror` to invoke `usebanner:codemirror`. This prevents the generic `usebanner` task from attempting to process files that have not yet been generated during the general CSS build phase.

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…endency.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 17 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Unprops Copilot for 7db8792

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 17 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants