From b54a88b94eaee764b636eae864e3fbe9c47ac4ec Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 30 Jan 2026 21:07:46 -0800 Subject: [PATCH 01/52] Modernize code-editor.js with const and let. This update replaces all 'var' declarations with 'const' or 'let' and adds the 'eslint-env es6' directive to ensure proper parsing by ESLint. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 46 +++++++++++++++--------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index bc570263858a8..b30021934df48 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -49,7 +49,8 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { * @return {Function} Update error notice function. */ function configureLinting( editor, settings ) { // eslint-disable-line complexity - var currentErrorAnnotations = [], previouslyShownErrorAnnotations = []; + let currentErrorAnnotations = []; + let previouslyShownErrorAnnotations = []; /** * Call the onUpdateErrorNotice if there are new errors to show. @@ -69,7 +70,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { * @return {Object} Lint options. */ function getLintOptions() { // eslint-disable-line complexity - var options = editor.getOption( 'lint' ); + let options = editor.getOption( 'lint' ); if ( ! options ) { return false; @@ -115,7 +116,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { // Wrap the onUpdateLinting CodeMirror event to route to onChangeLintingErrors and onUpdateErrorNotice. options.onUpdateLinting = (function( onUpdateLintingOverridden ) { return function( annotations, annotationsSorted, cm ) { - var errorAnnotations = _.filter( annotations, function( annotation ) { + const errorAnnotations = _.filter( annotations, function( annotation ) { return 'error' === annotation.severity; } ); @@ -153,12 +154,12 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { // Keep lint options populated. editor.on( 'optionChange', function( cm, option ) { - var options, gutters, gutterName = 'CodeMirror-lint-markers'; + const gutterName = 'CodeMirror-lint-markers'; if ( 'lint' !== option ) { return; } - gutters = editor.getOption( 'gutters' ) || []; - options = editor.getOption( 'lint' ); + const gutters = editor.getOption( 'gutters' ) || []; + const options = editor.getOption( 'lint' ); if ( true === options ) { if ( ! _.contains( gutters, gutterName ) ) { editor.setOption( 'gutters', [ gutterName ].concat( gutters ) ); @@ -185,7 +186,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { editor.off( 'blur', updateErrorNotice ); } ); editor.on( 'endCompletion', function() { - var editorRefocusWait = 500; + const editorRefocusWait = 500; editor.on( 'blur', updateErrorNotice ); // Wait for editor to possibly get re-focused after selection. @@ -225,13 +226,14 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { * @return {void} */ function configureTabbing( codemirror, settings ) { - var $textarea = $( codemirror.getTextArea() ); + const $textarea = $( codemirror.getTextArea() ); codemirror.on( 'blur', function() { $textarea.data( 'next-tab-blurs', false ); }); codemirror.on( 'keydown', function onKeydown( editor, event ) { - var tabKeyCode = 9, escKeyCode = 27; + const tabKeyCode = 9; + const escKeyCode = 27; // Take note of the ESC keypress so that the next TAB can focus outside the editor. if ( escKeyCode === event.keyCode ) { @@ -285,21 +287,21 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { * @return {CodeEditorInstance} Instance. */ wp.codeEditor.initialize = function initialize( textarea, settings ) { - var $textarea, codemirror, instanceSettings, instance, updateErrorNotice; + let $textarea; if ( 'string' === typeof textarea ) { $textarea = $( '#' + textarea ); } else { $textarea = $( textarea ); } - instanceSettings = $.extend( {}, wp.codeEditor.defaultSettings, settings ); + const instanceSettings = $.extend( {}, wp.codeEditor.defaultSettings, settings ); instanceSettings.codemirror = $.extend( {}, instanceSettings.codemirror ); - codemirror = wp.CodeMirror.fromTextArea( $textarea[0], instanceSettings.codemirror ); + const codemirror = wp.CodeMirror.fromTextArea( $textarea[0], instanceSettings.codemirror ); - updateErrorNotice = configureLinting( codemirror, instanceSettings ); + const updateErrorNotice = configureLinting( codemirror, instanceSettings ); - instance = { + const instance = { settings: instanceSettings, codemirror, updateErrorNotice, @@ -307,8 +309,6 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { if ( codemirror.showHint ) { codemirror.on( 'inputRead', function( editor, change ) { - var shouldAutocomplete, isAlphaKey, lineBeforeCursor, innerMode, token, char; - // Only trigger autocompletion for typed input or IME composition. if ( '+input' !== change.origin && ! change.origin.startsWith( '*compose' ) ) { return; @@ -321,21 +321,21 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { return; } - char = change.text[0]; - isAlphaKey = /^[a-zA-Z]$/.test( char ); - + const char = change.text[0]; + const isAlphaKey = /^[a-zA-Z]$/.test( char ); if ( codemirror.state.completionActive && isAlphaKey ) { return; } // Prevent autocompletion in string literals or comments. - token = codemirror.getTokenAt( codemirror.getCursor() ); + const token = codemirror.getTokenAt( codemirror.getCursor() ); if ( 'string' === token.type || 'comment' === token.type ) { return; } - innerMode = wp.CodeMirror.innerMode( codemirror.getMode(), token.state ).mode.name; - lineBeforeCursor = codemirror.doc.getLine( codemirror.doc.getCursor().line ).substr( 0, codemirror.doc.getCursor().ch ); + const innerMode = wp.CodeMirror.innerMode( codemirror.getMode(), token.state ).mode.name; + const lineBeforeCursor = codemirror.doc.getLine( codemirror.doc.getCursor().line ).substr( 0, codemirror.doc.getCursor().ch ); + let shouldAutocomplete; if ( 'html' === innerMode || 'xml' === innerMode ) { shouldAutocomplete = ( '<' === char || @@ -369,4 +369,4 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { return instance; }; -})( window.jQuery, window.wp ); +})( window.jQuery, window.wp ); \ No newline at end of file From ce4192b5d83fc03a58f985d019f823730a65f0af Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 30 Jan 2026 21:14:16 -0800 Subject: [PATCH 02/52] Code Editor: Fix JSDoc types for CodeMirror instances. Updates the JSDoc types from {CodeMirror} to {CodeMirror.Editor} for editor instances to correctly reference the instance interface instead of the namespace. This resolves typing issues in IDEs where methods like getOption() were reported as unresolved. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index b30021934df48..b235b654a4ee4 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -40,11 +40,11 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { /** * Configure linting. * - * @param {CodeMirror} editor - Editor. - * @param {Object} settings - Code editor settings. - * @param {Object} settings.codeMirror - Settings for CodeMirror. - * @param {Function} settings.onChangeLintingErrors - Callback for when there are changes to linting errors. - * @param {Function} settings.onUpdateErrorNotice - Callback to update error notice. + * @param {CodeMirror.Editor} editor - Editor. + * @param {Object} settings - Code editor settings. + * @param {Object} settings.codeMirror - Settings for CodeMirror. + * @param {Function} settings.onChangeLintingErrors - Callback for when there are changes to linting errors. + * @param {Function} settings.onUpdateErrorNotice - Callback to update error notice. * * @return {Function} Update error notice function. */ @@ -217,11 +217,11 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { /** * Configure tabbing. * - * @param {CodeMirror} codemirror - Editor. - * @param {Object} settings - Code editor settings. - * @param {Object} settings.codeMirror - Settings for CodeMirror. - * @param {Function} settings.onTabNext - Callback to handle tabbing to the next tabbable element. - * @param {Function} settings.onTabPrevious - Callback to handle tabbing to the previous tabbable element. + * @param {CodeMirror.Editor} codemirror - Editor. + * @param {Object} settings - Code editor settings. + * @param {Object} settings.codeMirror - Settings for CodeMirror. + * @param {Function} settings.onTabNext - Callback to handle tabbing to the next tabbable element. + * @param {Function} settings.onTabPrevious - Callback to handle tabbing to the previous tabbable element. * * @return {void} */ @@ -264,7 +264,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { /** * @typedef {object} wp.codeEditor~CodeEditorInstance * @property {object} settings - The code editor settings. - * @property {CodeMirror} codemirror - The CodeMirror instance. + * @property {CodeMirror.Editor} codemirror - The CodeMirror instance. * @property {Function} updateErrorNotice - Force update the error notice. */ @@ -369,4 +369,4 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { return instance; }; -})( window.jQuery, window.wp ); \ No newline at end of file +})( window.jQuery, window.wp ); From ef4352c82346a13a805527edf56f319320e5ec2c Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 10 Feb 2026 15:38:57 -0800 Subject: [PATCH 03/52] Replace deprecated substr() with slice(). Replaces the deprecated String.prototype.substr() method with slice() in code-editor.js to adhere to modern JavaScript best practices and resolve editor warnings. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index b235b654a4ee4..adb67c42be46b 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -334,7 +334,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { } const innerMode = wp.CodeMirror.innerMode( codemirror.getMode(), token.state ).mode.name; - const lineBeforeCursor = codemirror.doc.getLine( codemirror.doc.getCursor().line ).substr( 0, codemirror.doc.getCursor().ch ); + const lineBeforeCursor = codemirror.doc.getLine( codemirror.doc.getCursor().line ).slice( 0, codemirror.doc.getCursor().ch ); let shouldAutocomplete; if ( 'html' === innerMode || 'xml' === innerMode ) { shouldAutocomplete = ( From c76450fb8d091727971df020785e610c1dad21ce Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 10 Feb 2026 15:41:41 -0800 Subject: [PATCH 04/52] Replace deprecated event.keyCode with event.key. Updates the keyboard event handling in code-editor.js to use the modern event.key property instead of the deprecated event.keyCode, following current web standards. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index adb67c42be46b..ebecb28ef0c9f 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -232,17 +232,14 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { $textarea.data( 'next-tab-blurs', false ); }); codemirror.on( 'keydown', function onKeydown( editor, event ) { - const tabKeyCode = 9; - const escKeyCode = 27; - // Take note of the ESC keypress so that the next TAB can focus outside the editor. - if ( escKeyCode === event.keyCode ) { + if ( 'Escape' === event.key ) { $textarea.data( 'next-tab-blurs', true ); return; } // Short-circuit if tab key is not being pressed or the tab key press should move focus. - if ( tabKeyCode !== event.keyCode || ! $textarea.data( 'next-tab-blurs' ) ) { + if ( 'Tab' !== event.key || ! $textarea.data( 'next-tab-blurs' ) ) { return; } From 68967d45fcee50a1e5890dc5f5ed8ad4a219c8dc Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 10 Feb 2026 15:51:14 -0800 Subject: [PATCH 05/52] Pass Underscore to IIFE and add JSDoc types. Resolves "Referenced UMD global variable" warnings in PhpStorm by passing window._ as a parameter to the IIFE and explicitly typing it with JSDoc. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++++++ package.json | 1 + src/js/_enqueues/wp/code-editor.js | 9 +++++++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index cae57f5937eca..dbccaa6b7c315 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,6 +46,7 @@ "@playwright/test": "1.56.1", "@pmmmwh/react-refresh-webpack-plugin": "0.6.1", "@types/codemirror": "5.60.17", + "@types/underscore": "1.11.15", "@wordpress/e2e-test-utils-playwright": "1.33.2", "@wordpress/prettier-config": "4.33.1", "@wordpress/scripts": "30.26.2", @@ -5448,6 +5449,13 @@ "integrity": "sha512-THo502dA5PzG/sfQH+42Lw3fvmYkceefOspdCwpHRul8ik2Jv1K8I5OZz1AT3/rs46kwgMCe9bSBmDLYkkOMGg==", "dev": true }, + "node_modules/@types/underscore": { + "version": "1.11.15", + "resolved": "https://registry.npmjs.org/@types/underscore/-/underscore-1.11.15.tgz", + "integrity": "sha512-HP38xE+GuWGlbSRq9WrZkousaQ7dragtZCruBVMi0oX1migFZavZ3OROKHSkNp/9ouq82zrWtZpg18jFnVN96g==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/ws": { "version": "8.5.10", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", diff --git a/package.json b/package.json index 766e241ff8d6d..d14ceba1336ea 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "@playwright/test": "1.56.1", "@pmmmwh/react-refresh-webpack-plugin": "0.6.1", "@types/codemirror": "5.60.17", + "@types/underscore": "1.11.15", "@wordpress/e2e-test-utils-playwright": "1.33.2", "@wordpress/prettier-config": "4.33.1", "@wordpress/scripts": "30.26.2", diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index ebecb28ef0c9f..244814a13e921 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -17,7 +17,12 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { window.wp.codeEditor = {}; } -( function( $, wp ) { +/** + * @param {jQuery} $ - jQuery. + * @param {object} wp - WordPress namespace. + * @param {import('underscore').UnderscoreStatic} _ - Underscore. + */ +( function( $, wp, _ ) { 'use strict'; /** @@ -366,4 +371,4 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { return instance; }; -})( window.jQuery, window.wp ); +})( window.jQuery, window.wp, window._ ); From 49ab652cfeb850f5130d1fdf7a87ab5d072b0a0b Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 10 Feb 2026 16:03:40 -0800 Subject: [PATCH 06/52] Define and use CodeEditorSettings typedef. Fleshes out the CodeEditorSettings type definition with properties for CodeMirror, CSSLint, JSHint, and HTMLHint based on the provided configuration object. Updates all settings parameter references to use this new type for improved editor intelligence. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 90 +++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 19 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index 244814a13e921..9f9ef15389e9e 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -29,7 +29,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { * Default settings for code editor. * * @since 4.9.0 - * @type {object} + * @type {CodeEditorSettings} */ wp.codeEditor.defaultSettings = { codemirror: {}, @@ -46,10 +46,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { * Configure linting. * * @param {CodeMirror.Editor} editor - Editor. - * @param {Object} settings - Code editor settings. - * @param {Object} settings.codeMirror - Settings for CodeMirror. - * @param {Function} settings.onChangeLintingErrors - Callback for when there are changes to linting errors. - * @param {Function} settings.onUpdateErrorNotice - Callback to update error notice. + * @param {CodeEditorSettings} settings - Code editor settings. * * @return {Function} Update error notice function. */ @@ -223,10 +220,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { * Configure tabbing. * * @param {CodeMirror.Editor} codemirror - Editor. - * @param {Object} settings - Code editor settings. - * @param {Object} settings.codeMirror - Settings for CodeMirror. - * @param {Function} settings.onTabNext - Callback to handle tabbing to the next tabbable element. - * @param {Function} settings.onTabPrevious - Callback to handle tabbing to the previous tabbable element. + * @param {CodeEditorSettings} settings - Code editor settings. * * @return {void} */ @@ -263,9 +257,75 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { }); } + /** + * Settings for the code editor. + * + * @typedef {object} CodeEditorSettings + * + * @property {object} codemirror - CodeMirror settings. + * @property {number} codemirror.indentUnit - Indent unit. + * @property {boolean} codemirror.indentWithTabs - Whether to indent with tabs. + * @property {string} codemirror.inputStyle - Input style. + * @property {boolean} codemirror.lineNumbers - Whether to show line numbers. + * @property {boolean} codemirror.lineWrapping - Whether to wrap lines. + * @property {boolean} codemirror.styleActiveLine - Whether to style active line. + * @property {boolean} codemirror.continueComments - Whether to continue comments. + * @property {Object} codemirror.extraKeys - Extra keys. + * @property {string} codemirror.direction - Text direction. + * @property {string[]} codemirror.gutters - Gutters. + * @property {string} codemirror.mode - Mode. + * @property {boolean|object} codemirror.lint - Whether to enable linting. + * @property {boolean} codemirror.autoCloseBrackets - Whether to auto-close brackets. + * @property {boolean} codemirror.matchBrackets - Whether to match brackets. + * + * @property {object} csslint - CSSLint rules. + * @property {boolean} csslint.errors - Errors. + * @property {boolean} [csslint.box-model] - Box model rules. + * @property {boolean} [csslint.display-property-grouping] - Display property grouping rules. + * @property {boolean} [csslint.duplicate-properties] - Duplicate properties rules. + * @property {boolean} [csslint.known-properties] - Known properties rules. + * @property {boolean} [csslint.outline-none] - Outline none rules. + * + * @property {object} jshint - JSHint rules. + * @property {number} jshint.esversion - ECMAScript version. + * @property {boolean} jshint.module - Whether to use modules. + * @property {boolean} jshint.boss - Whether to allow assignments in control expressions. + * @property {boolean} jshint.curly - Whether to require curly braces. + * @property {boolean} jshint.eqeqeq - Whether to require === and !==. + * @property {boolean} jshint.eqnull - Whether to allow == null. + * @property {boolean} jshint.expr - Whether to allow expressions. + * @property {boolean} jshint.immed - Whether to require immediate function invocation. + * @property {boolean} jshint.noarg - Whether to prohibit arguments.caller/callee. + * @property {boolean} jshint.nonbsp - Whether to prohibit non-breaking spaces. + * @property {string} jshint.quotmark - Quote mark preference. + * @property {boolean} jshint.undef - Whether to prohibit undefined variables. + * @property {boolean} jshint.unused - Whether to prohibit unused variables. + * @property {boolean} jshint.browser - Whether to enable browser globals. + * @property {Object} jshint.globals - Global variables. + * + * @property {object} htmlhint - HTMLHint rules. + * @property {boolean} [htmlhint.tagname-lowercase] - Tag name lowercase rules. + * @property {boolean} [htmlhint.attr-lowercase] - Attribute lowercase rules. + * @property {boolean} [htmlhint.attr-value-double-quotes] - Attribute value double quotes rules. + * @property {boolean} [htmlhint.doctype-first] - Doctype first rules. + * @property {boolean} [htmlhint.tag-pair] - Tag pair rules. + * @property {boolean} [htmlhint.spec-char-escape] - Spec char escape rules. + * @property {boolean} [htmlhint.id-unique] - ID unique rules. + * @property {boolean} [htmlhint.src-not-empty] - Src not empty rules. + * @property {boolean} [htmlhint.attr-no-duplication] - Attribute no duplication rules. + * @property {boolean} [htmlhint.alt-require] - Alt require rules. + * @property {string} [htmlhint.space-tab-mixed-disabled] - Space tab mixed disabled rules. + * @property {boolean} [htmlhint.attr-unsafe-chars] - Attribute unsafe chars rules. + * + * @property {Function} [onTabNext] - Callback to handle tabbing to the next tabbable element. + * @property {Function} [onTabPrevious] - Callback to handle tabbing to the previous tabbable element. + * @property {Function} [onChangeLintingErrors] - Callback for when the linting errors have changed. + * @property {Function} [onUpdateErrorNotice] - Callback for when error notice should be displayed. + */ + /** * @typedef {object} wp.codeEditor~CodeEditorInstance - * @property {object} settings - The code editor settings. + * @property {CodeEditorSettings} settings - The code editor settings. * @property {CodeMirror.Editor} codemirror - The CodeMirror instance. * @property {Function} updateErrorNotice - Force update the error notice. */ @@ -276,15 +336,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { * @since 4.9.0 * * @param {string|jQuery|Element} textarea - The HTML id, jQuery object, or DOM Element for the textarea that is used for the editor. - * @param {Object} [settings] - Settings to override defaults. - * @param {Function} [settings.onChangeLintingErrors] - Callback for when the linting errors have changed. - * @param {Function} [settings.onUpdateErrorNotice] - Callback for when error notice should be displayed. - * @param {Function} [settings.onTabPrevious] - Callback to handle tabbing to the previous tabbable element. - * @param {Function} [settings.onTabNext] - Callback to handle tabbing to the next tabbable element. - * @param {Object} [settings.codemirror] - Options for CodeMirror. - * @param {Object} [settings.csslint] - Rules for CSSLint. - * @param {Object} [settings.htmlhint] - Rules for HTMLHint. - * @param {Object} [settings.jshint] - Rules for JSHint. + * @param {CodeEditorSettings} [settings] - Settings to override defaults. * * @return {CodeEditorInstance} Instance. */ From d3d39e997cde2db412384d3d4f7c5e81c96ca3ef Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 10 Feb 2026 16:06:09 -0800 Subject: [PATCH 07/52] Make CodeEditorSettings sub-properties optional. Resolves type mismatch errors in PhpStorm by marking nested properties in the CodeEditorSettings typedef as optional. This allows empty objects to be assigned to these properties in defaultSettings while maintaining autocompletion support. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 68 +++++++++++++++--------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index 9f9ef15389e9e..173d6d2184749 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -262,48 +262,48 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { * * @typedef {object} CodeEditorSettings * - * @property {object} codemirror - CodeMirror settings. - * @property {number} codemirror.indentUnit - Indent unit. - * @property {boolean} codemirror.indentWithTabs - Whether to indent with tabs. - * @property {string} codemirror.inputStyle - Input style. - * @property {boolean} codemirror.lineNumbers - Whether to show line numbers. - * @property {boolean} codemirror.lineWrapping - Whether to wrap lines. - * @property {boolean} codemirror.styleActiveLine - Whether to style active line. - * @property {boolean} codemirror.continueComments - Whether to continue comments. - * @property {Object} codemirror.extraKeys - Extra keys. - * @property {string} codemirror.direction - Text direction. - * @property {string[]} codemirror.gutters - Gutters. - * @property {string} codemirror.mode - Mode. - * @property {boolean|object} codemirror.lint - Whether to enable linting. - * @property {boolean} codemirror.autoCloseBrackets - Whether to auto-close brackets. - * @property {boolean} codemirror.matchBrackets - Whether to match brackets. + * @property {object} [codemirror] - CodeMirror settings. + * @property {number} [codemirror.indentUnit] - Indent unit. + * @property {boolean} [codemirror.indentWithTabs] - Whether to indent with tabs. + * @property {string} [codemirror.inputStyle] - Input style. + * @property {boolean} [codemirror.lineNumbers] - Whether to show line numbers. + * @property {boolean} [codemirror.lineWrapping] - Whether to wrap lines. + * @property {boolean} [codemirror.styleActiveLine] - Whether to style active line. + * @property {boolean} [codemirror.continueComments] - Whether to continue comments. + * @property {Object} [codemirror.extraKeys] - Extra keys. + * @property {string} [codemirror.direction] - Text direction. + * @property {string[]} [codemirror.gutters] - Gutters. + * @property {string} [codemirror.mode] - Mode. + * @property {boolean|object} [codemirror.lint] - Whether to enable linting. + * @property {boolean} [codemirror.autoCloseBrackets] - Whether to auto-close brackets. + * @property {boolean} [codemirror.matchBrackets] - Whether to match brackets. * - * @property {object} csslint - CSSLint rules. - * @property {boolean} csslint.errors - Errors. + * @property {object} [csslint] - CSSLint rules. + * @property {boolean} [csslint.errors] - Errors. * @property {boolean} [csslint.box-model] - Box model rules. * @property {boolean} [csslint.display-property-grouping] - Display property grouping rules. * @property {boolean} [csslint.duplicate-properties] - Duplicate properties rules. * @property {boolean} [csslint.known-properties] - Known properties rules. * @property {boolean} [csslint.outline-none] - Outline none rules. * - * @property {object} jshint - JSHint rules. - * @property {number} jshint.esversion - ECMAScript version. - * @property {boolean} jshint.module - Whether to use modules. - * @property {boolean} jshint.boss - Whether to allow assignments in control expressions. - * @property {boolean} jshint.curly - Whether to require curly braces. - * @property {boolean} jshint.eqeqeq - Whether to require === and !==. - * @property {boolean} jshint.eqnull - Whether to allow == null. - * @property {boolean} jshint.expr - Whether to allow expressions. - * @property {boolean} jshint.immed - Whether to require immediate function invocation. - * @property {boolean} jshint.noarg - Whether to prohibit arguments.caller/callee. - * @property {boolean} jshint.nonbsp - Whether to prohibit non-breaking spaces. - * @property {string} jshint.quotmark - Quote mark preference. - * @property {boolean} jshint.undef - Whether to prohibit undefined variables. - * @property {boolean} jshint.unused - Whether to prohibit unused variables. - * @property {boolean} jshint.browser - Whether to enable browser globals. - * @property {Object} jshint.globals - Global variables. + * @property {object} [jshint] - JSHint rules. + * @property {number} [jshint.esversion] - ECMAScript version. + * @property {boolean} [jshint.module] - Whether to use modules. + * @property {boolean} [jshint.boss] - Whether to allow assignments in control expressions. + * @property {boolean} [jshint.curly] - Whether to require curly braces. + * @property {boolean} [jshint.eqeqeq] - Whether to require === and !==. + * @property {boolean} [jshint.eqnull] - Whether to allow == null. + * @property {boolean} [jshint.expr] - Whether to allow expressions. + * @property {boolean} [jshint.immed] - Whether to require immediate function invocation. + * @property {boolean} [jshint.noarg] - Whether to prohibit arguments.caller/callee. + * @property {boolean} [jshint.nonbsp] - Whether to prohibit non-breaking spaces. + * @property {string} [jshint.quotmark] - Quote mark preference. + * @property {boolean} [jshint.undef] - Whether to prohibit undefined variables. + * @property {boolean} [jshint.unused] - Whether to prohibit unused variables. + * @property {boolean} [jshint.browser] - Whether to enable browser globals. + * @property {Object} [jshint.globals] - Global variables. * - * @property {object} htmlhint - HTMLHint rules. + * @property {object} [htmlhint] - HTMLHint rules. * @property {boolean} [htmlhint.tagname-lowercase] - Tag name lowercase rules. * @property {boolean} [htmlhint.attr-lowercase] - Attribute lowercase rules. * @property {boolean} [htmlhint.attr-value-double-quotes] - Attribute value double quotes rules. From 7bd58f0d21030dd90b4c23627084579e63a9ec2b Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 10 Feb 2026 16:10:39 -0800 Subject: [PATCH 08/52] Refine CodeEditorInstance and initialize types. Updates CodeEditorInstance to use CodeMirror.EditorFromTextArea and explicitly types local variables in wp.codeEditor.initialize to resolve assignability warnings in PhpStorm. Switched to a deep extend for instanceSettings to ensure nested configuration objects are correctly handled. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index 173d6d2184749..a2d7524c1324c 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -326,7 +326,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { /** * @typedef {object} wp.codeEditor~CodeEditorInstance * @property {CodeEditorSettings} settings - The code editor settings. - * @property {CodeMirror.Editor} codemirror - The CodeMirror instance. + * @property {CodeMirror.EditorFromTextArea} codemirror - The CodeMirror instance. * @property {Function} updateErrorNotice - Force update the error notice. */ @@ -338,7 +338,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { * @param {string|jQuery|Element} textarea - The HTML id, jQuery object, or DOM Element for the textarea that is used for the editor. * @param {CodeEditorSettings} [settings] - Settings to override defaults. * - * @return {CodeEditorInstance} Instance. + * @return {wp.codeEditor~CodeEditorInstance} Instance. */ wp.codeEditor.initialize = function initialize( textarea, settings ) { let $textarea; @@ -348,13 +348,14 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { $textarea = $( textarea ); } - const instanceSettings = $.extend( {}, wp.codeEditor.defaultSettings, settings ); - instanceSettings.codemirror = $.extend( {}, instanceSettings.codemirror ); + /** @type {CodeEditorSettings} */ + const instanceSettings = $.extend( true, {}, wp.codeEditor.defaultSettings, settings ); const codemirror = wp.CodeMirror.fromTextArea( $textarea[0], instanceSettings.codemirror ); const updateErrorNotice = configureLinting( codemirror, instanceSettings ); + /** @type {wp.codeEditor~CodeEditorInstance} */ const instance = { settings: instanceSettings, codemirror, From 1569be39dd0f7f3bc459d15fd3328c6e2c8587c7 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 10 Feb 2026 16:14:13 -0800 Subject: [PATCH 09/52] Refine CodeMirror settings types in CodeEditorSettings. Updates the CodeEditorSettings typedef to use the official CodeMirror.EditorConfiguration type for the codemirror property and adds specific string literal types for direction and inputStyle. This resolves type assignability errors in PhpStorm. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index a2d7524c1324c..94e8079d95a1d 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -262,18 +262,18 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { * * @typedef {object} CodeEditorSettings * - * @property {object} [codemirror] - CodeMirror settings. + * @property {import('codemirror').EditorConfiguration} [codemirror] - CodeMirror settings. * @property {number} [codemirror.indentUnit] - Indent unit. * @property {boolean} [codemirror.indentWithTabs] - Whether to indent with tabs. - * @property {string} [codemirror.inputStyle] - Input style. + * @property {'textarea'|'contenteditable'} [codemirror.inputStyle] - Input style. * @property {boolean} [codemirror.lineNumbers] - Whether to show line numbers. * @property {boolean} [codemirror.lineWrapping] - Whether to wrap lines. * @property {boolean} [codemirror.styleActiveLine] - Whether to style active line. * @property {boolean} [codemirror.continueComments] - Whether to continue comments. * @property {Object} [codemirror.extraKeys] - Extra keys. - * @property {string} [codemirror.direction] - Text direction. + * @property {'ltr'|'rtl'} [codemirror.direction] - Text direction. * @property {string[]} [codemirror.gutters] - Gutters. - * @property {string} [codemirror.mode] - Mode. + * @property {string|object} [codemirror.mode] - Mode. * @property {boolean|object} [codemirror.lint] - Whether to enable linting. * @property {boolean} [codemirror.autoCloseBrackets] - Whether to auto-close brackets. * @property {boolean} [codemirror.matchBrackets] - Whether to match brackets. From 55a86e967aa39e488f02b9a4f41037f153bdc454 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 10 Feb 2026 16:16:23 -0800 Subject: [PATCH 10/52] Use public CodeMirror API for wrapper element. Replaces the internal editor.display.wrapper property with the public editor.getWrapperElement() method to resolve unresolved variable warnings in IDEs. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index 94e8079d95a1d..c01d9127ca4b6 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -208,7 +208,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { * called. */ $( document.body ).on( 'mousedown', function( event ) { - if ( editor.state.focused && ! $.contains( editor.display.wrapper, event.target ) && ! $( event.target ).hasClass( 'CodeMirror-hint' ) ) { + if ( editor.state.focused && ! $.contains( editor.getWrapperElement(), event.target ) && ! $( event.target ).hasClass( 'CodeMirror-hint' ) ) { updateErrorNotice(); } }); From d2dddabf029f1cccb67bc220b86cb8ae143c0198 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 10 Feb 2026 16:17:36 -0800 Subject: [PATCH 11/52] Use native Node.contains() instead of jQuery.contains(). Replaces the jQuery.contains() call with the native DOM element.contains() method. This resolves a parameter mismatch error in some IDEs and leverages modern native APIs. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index c01d9127ca4b6..70511943327f8 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -208,7 +208,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { * called. */ $( document.body ).on( 'mousedown', function( event ) { - if ( editor.state.focused && ! $.contains( editor.getWrapperElement(), event.target ) && ! $( event.target ).hasClass( 'CodeMirror-hint' ) ) { + if ( editor.state.focused && ! editor.getWrapperElement().contains( event.target ) && ! $( event.target ).hasClass( 'CodeMirror-hint' ) ) { updateErrorNotice(); } }); From 7bdadc77653f0dddd9b0e60043e17fbaba48a4f6 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 10 Feb 2026 16:20:19 -0800 Subject: [PATCH 12/52] Use native Element.classList instead of jQuery.hasClass(). Replaces the jQuery.hasClass() call with the native classList.contains() method. This follows modern JavaScript practices and removes an unnecessary jQuery dependency for this check. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index 70511943327f8..5e067bb134150 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -208,7 +208,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { * called. */ $( document.body ).on( 'mousedown', function( event ) { - if ( editor.state.focused && ! editor.getWrapperElement().contains( event.target ) && ! $( event.target ).hasClass( 'CodeMirror-hint' ) ) { + if ( editor.state.focused && ! editor.getWrapperElement().contains( event.target ) && ! event.target.classList.contains( 'CodeMirror-hint' ) ) { updateErrorNotice(); } }); From 7aa5359d9efbd08d6ae8885b9e4f132bf2a9ed37 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 10 Feb 2026 16:27:57 -0800 Subject: [PATCH 13/52] Fix logic error when calling overridden onUpdateLinting. Replaces the invalid onUpdateLintingOverridden.apply() call with a direct function call. The previous usage incorrectly attempted to pass three arguments to apply() and used the annotations array as the 'this' context. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index 5e067bb134150..b7883621967b3 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -123,7 +123,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { } ); if ( onUpdateLintingOverridden ) { - onUpdateLintingOverridden.apply( annotations, annotationsSorted, cm ); + onUpdateLintingOverridden( annotations, annotationsSorted, cm ); } // Skip if there are no changes to the errors. From 0eab515a7fc5da1fb32aca9d6a295a260814e935 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 10 Feb 2026 16:30:52 -0800 Subject: [PATCH 14/52] Use specific CodeMirror.EditorFromTextArea type for editor instances. Updates the JSDoc types for editor parameters in configureLinting and configureTabbing to use CodeMirror.EditorFromTextArea. This resolves unresolved method warnings in PhpStorm for getTextArea() and ensures correct typing for instances created via fromTextArea(). Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index b7883621967b3..dea3e795455ac 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -45,7 +45,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { /** * Configure linting. * - * @param {CodeMirror.Editor} editor - Editor. + * @param {CodeMirror.EditorFromTextArea} editor - Editor. * @param {CodeEditorSettings} settings - Code editor settings. * * @return {Function} Update error notice function. @@ -219,7 +219,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { /** * Configure tabbing. * - * @param {CodeMirror.Editor} codemirror - Editor. + * @param {CodeMirror.EditorFromTextArea} codemirror - Editor. * @param {CodeEditorSettings} settings - Code editor settings. * * @return {void} From c3f6261264edcc7e3541cd41b786da84d4eeda0f Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 10 Feb 2026 16:34:22 -0800 Subject: [PATCH 15/52] Fix unresolved performLint() and improve CodeMirror types. Updates JSDoc types to include optional performLint and showHint methods provided by CodeMirror addons. Adds a check for performLint existence before calling it to ensure safety and resolve IDE warnings. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index dea3e795455ac..55f6e80d5ef12 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -45,7 +45,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { /** * Configure linting. * - * @param {CodeMirror.EditorFromTextArea} editor - Editor. + * @param {CodeMirror.EditorFromTextArea & { performLint?: function }} editor - Editor. * @param {CodeEditorSettings} settings - Code editor settings. * * @return {Function} Update error notice function. @@ -172,7 +172,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { } // Force update on error notice to show or hide. - if ( editor.getOption( 'lint' ) ) { + if ( editor.getOption( 'lint' ) && editor.performLint ) { editor.performLint(); } else { currentErrorAnnotations = []; @@ -326,7 +326,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { /** * @typedef {object} wp.codeEditor~CodeEditorInstance * @property {CodeEditorSettings} settings - The code editor settings. - * @property {CodeMirror.EditorFromTextArea} codemirror - The CodeMirror instance. + * @property {CodeMirror.EditorFromTextArea & { performLint?: function, showHint?: function }} codemirror - The CodeMirror instance. * @property {Function} updateErrorNotice - Force update the error notice. */ From dfffb19146b80bb3d7062fc11ecc5378ab957da7 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 10 Feb 2026 16:42:01 -0800 Subject: [PATCH 16/52] Use native filter() for annotations to improve type inference. Replaces _.filter() with the native Array.prototype.filter() method. This helps PhpStorm correctly infer the type of the annotation object from the LintAnnotation[] array, resolving issues where it was incorrectly identified as a string. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index 55f6e80d5ef12..a8baa1b54c5bf 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -117,8 +117,13 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { // Wrap the onUpdateLinting CodeMirror event to route to onChangeLintingErrors and onUpdateErrorNotice. options.onUpdateLinting = (function( onUpdateLintingOverridden ) { + /** + * @param {LintAnnotation[]} annotations - Annotations. + * @param {LintAnnotation[]} annotationsSorted - Sorted annotations. + * @param {CodeMirror.Editor} cm - Editor. + */ return function( annotations, annotationsSorted, cm ) { - const errorAnnotations = _.filter( annotations, function( annotation ) { + const errorAnnotations = annotations.filter( function( annotation ) { return 'error' === annotation.severity; } ); @@ -258,8 +263,14 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { } /** - * Settings for the code editor. - * + * @typedef {object} LintAnnotation + * @property {string} message - Message. + * @property {'error'|'warning'} severity - Severity. + * @property {import('codemirror').Position} from - From position. + * @property {import('codemirror').Position} to - To position. + */ + + /** * @typedef {object} CodeEditorSettings * * @property {import('codemirror').EditorConfiguration} [codemirror] - CodeMirror settings. From 651b32525cc37729733651e91013df99a4df7a98 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 10 Feb 2026 16:47:14 -0800 Subject: [PATCH 17/52] Add types for CodeMirror state and token state. Defines CodeMirrorState and CodeMirrorTokenState typedefs to document properties added by addons (completionActive) and mode-specific states (htmlState, curState). Applies these types to the CodeMirror instance and token variable to resolve unresolved variable warnings in PhpStorm. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index a8baa1b54c5bf..3cb6095a9d2a2 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -270,6 +270,18 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { * @property {import('codemirror').Position} to - To position. */ + /** + * @typedef {object} CodeMirrorState + * @property {boolean} [completionActive] - Whether completion is active. + */ + + /** + * @typedef {object} CodeMirrorTokenState + * @property {object} [htmlState] - HTML state. + * @property {string} [htmlState.tagName] - Tag name. + * @property {CodeMirrorTokenState} [curState] - Current state. + */ + /** * @typedef {object} CodeEditorSettings * @@ -337,7 +349,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { /** * @typedef {object} wp.codeEditor~CodeEditorInstance * @property {CodeEditorSettings} settings - The code editor settings. - * @property {CodeMirror.EditorFromTextArea & { performLint?: function, showHint?: function }} codemirror - The CodeMirror instance. + * @property {CodeMirror.EditorFromTextArea & { performLint?: function, showHint?: function, state: CodeMirrorState }} codemirror - The CodeMirror instance. * @property {Function} updateErrorNotice - Force update the error notice. */ @@ -394,7 +406,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { } // Prevent autocompletion in string literals or comments. - const token = codemirror.getTokenAt( codemirror.getCursor() ); + const token = /** @type {import('codemirror').Token & { state: CodeMirrorTokenState }} */ ( codemirror.getTokenAt( codemirror.getCursor() ) ); if ( 'string' === token.type || 'comment' === token.type ) { return; } From cfa9f8afa9d2981650a9a4f224444e15c3bb9e48 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 10 Feb 2026 17:05:10 -0800 Subject: [PATCH 18/52] Enhance CodeMirror type definitions for better IDE compatibility. - Refines the CodeMirrorEditor typedef as a standalone interface with relaxed string signatures for getOption, setOption, on, and off, resolving string assignability warnings in PhpStorm. - Introduces CodeMirrorSettings to correctly extend EditorConfiguration with addon-specific properties. - Updates JSDoc for IIFE parameters and internal functions to use these more precise types. - Adds the 'focused' property to CodeMirrorState. - Explicitly types the CodeMirror instance in wp.codeEditor.initialize. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 60 +++++++++++++++++++----------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index 3cb6095a9d2a2..8646564da459e 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -19,7 +19,8 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { /** * @param {jQuery} $ - jQuery. - * @param {object} wp - WordPress namespace. + * @param {Object} wp - WordPress namespace. + * @param {import('codemirror')} wp.CodeMirror - CodeMirror. * @param {import('underscore').UnderscoreStatic} _ - Underscore. */ ( function( $, wp, _ ) { @@ -45,7 +46,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { /** * Configure linting. * - * @param {CodeMirror.EditorFromTextArea & { performLint?: function }} editor - Editor. + * @param {CodeMirrorEditor} editor - Editor. * @param {CodeEditorSettings} settings - Code editor settings. * * @return {Function} Update error notice function. @@ -120,7 +121,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { /** * @param {LintAnnotation[]} annotations - Annotations. * @param {LintAnnotation[]} annotationsSorted - Sorted annotations. - * @param {CodeMirror.Editor} cm - Editor. + * @param {CodeMirrorEditor} cm - Editor. */ return function( annotations, annotationsSorted, cm ) { const errorAnnotations = annotations.filter( function( annotation ) { @@ -224,7 +225,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { /** * Configure tabbing. * - * @param {CodeMirror.EditorFromTextArea} codemirror - Editor. + * @param {CodeMirrorEditor} codemirror - Editor. * @param {CodeEditorSettings} settings - Code editor settings. * * @return {void} @@ -273,6 +274,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { /** * @typedef {object} CodeMirrorState * @property {boolean} [completionActive] - Whether completion is active. + * @property {boolean} [focused] - Whether the editor is focused. */ /** @@ -283,24 +285,21 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { */ /** - * @typedef {object} CodeEditorSettings + * @typedef {import('codemirror').EditorConfiguration & { + * lint?: boolean | object, + * autoCloseBrackets?: boolean, + * matchBrackets?: boolean, + * continueComments?: boolean, + * styleActiveLine?: boolean + * }} CodeMirrorSettings + */ + + /** + * Settings for the code editor. * - * @property {import('codemirror').EditorConfiguration} [codemirror] - CodeMirror settings. - * @property {number} [codemirror.indentUnit] - Indent unit. - * @property {boolean} [codemirror.indentWithTabs] - Whether to indent with tabs. - * @property {'textarea'|'contenteditable'} [codemirror.inputStyle] - Input style. - * @property {boolean} [codemirror.lineNumbers] - Whether to show line numbers. - * @property {boolean} [codemirror.lineWrapping] - Whether to wrap lines. - * @property {boolean} [codemirror.styleActiveLine] - Whether to style active line. - * @property {boolean} [codemirror.continueComments] - Whether to continue comments. - * @property {Object} [codemirror.extraKeys] - Extra keys. - * @property {'ltr'|'rtl'} [codemirror.direction] - Text direction. - * @property {string[]} [codemirror.gutters] - Gutters. - * @property {string|object} [codemirror.mode] - Mode. - * @property {boolean|object} [codemirror.lint] - Whether to enable linting. - * @property {boolean} [codemirror.autoCloseBrackets] - Whether to auto-close brackets. - * @property {boolean} [codemirror.matchBrackets] - Whether to match brackets. + * @typedef {object} CodeEditorSettings * + * @property {CodeMirrorSettings} [codemirror] - CodeMirror settings. * @property {object} [csslint] - CSSLint rules. * @property {boolean} [csslint.errors] - Errors. * @property {boolean} [csslint.box-model] - Box model rules. @@ -346,10 +345,28 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { * @property {Function} [onUpdateErrorNotice] - Callback for when error notice should be displayed. */ + /** + * @typedef {Object} CodeMirrorEditor + * @property {import('codemirror').Doc} doc - Document. + * @property {CodeMirrorState} state - State. + * @property {CodeMirrorSettings} options - Options. + * @property {function(string):*} getOption - Get option. + * @property {function(string, *):void} setOption - Set option. + * @property {function(string, function):void} on - On event. + * @property {function(string, function):void} off - Off event. + * @property {function():void} [performLint] - Perform lint. + * @property {function(object):void} [showHint] - Show hint. + * @property {function():object} getMode - Get mode. + * @property {function():import('codemirror').Position} getCursor - Get cursor. + * @property {function(import('codemirror').Position):import('codemirror').Token} getTokenAt - Get token at. + * @property {function():HTMLElement} getWrapperElement - Get wrapper element. + * @property {function():HTMLTextAreaElement} getTextArea - Get text area. + */ + /** * @typedef {object} wp.codeEditor~CodeEditorInstance * @property {CodeEditorSettings} settings - The code editor settings. - * @property {CodeMirror.EditorFromTextArea & { performLint?: function, showHint?: function, state: CodeMirrorState }} codemirror - The CodeMirror instance. + * @property {CodeMirrorEditor} codemirror - The CodeMirror instance. * @property {Function} updateErrorNotice - Force update the error notice. */ @@ -374,6 +391,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { /** @type {CodeEditorSettings} */ const instanceSettings = $.extend( true, {}, wp.codeEditor.defaultSettings, settings ); + /** @type {CodeMirrorEditor} */ const codemirror = wp.CodeMirror.fromTextArea( $textarea[0], instanceSettings.codemirror ); const updateErrorNotice = configureLinting( codemirror, instanceSettings ); From 81db3048e490b78e82d40db7882ae5217f6fa195 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 10 Feb 2026 17:07:53 -0800 Subject: [PATCH 19/52] Ensure shouldAutocomplete is always boolean. Initializes shouldAutocomplete to false and uses boolean coercion for the HTML tag name check. This makes the code more robust and ensures the variable consistent with its intended purpose as a boolean flag. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index 8646564da459e..c921fd64a029d 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -431,14 +431,14 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { const innerMode = wp.CodeMirror.innerMode( codemirror.getMode(), token.state ).mode.name; const lineBeforeCursor = codemirror.doc.getLine( codemirror.doc.getCursor().line ).slice( 0, codemirror.doc.getCursor().ch ); - let shouldAutocomplete; + let shouldAutocomplete = false; if ( 'html' === innerMode || 'xml' === innerMode ) { shouldAutocomplete = ( '<' === char || ( '/' === char && 'tag' === token.type ) || ( isAlphaKey && 'tag' === token.type ) || ( isAlphaKey && 'attribute' === token.type ) || - ( '=' === char && ( + ( '=' === char && !! ( token.state.htmlState?.tagName || token.state.curState?.htmlState?.tagName ) ) From c4cb899423cf7614deebacc4e244cc097a64b077 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Wed, 11 Feb 2026 12:38:19 -0800 Subject: [PATCH 20/52] Use getDoc method --- src/js/_enqueues/wp/code-editor.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index c921fd64a029d..6c9e558e37d0e 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -430,7 +430,8 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { } const innerMode = wp.CodeMirror.innerMode( codemirror.getMode(), token.state ).mode.name; - const lineBeforeCursor = codemirror.doc.getLine( codemirror.doc.getCursor().line ).slice( 0, codemirror.doc.getCursor().ch ); + const doc = codemirror.getDoc(); + const lineBeforeCursor = doc.getLine( doc.getCursor().line ).slice( 0, doc.getCursor().ch ); let shouldAutocomplete = false; if ( 'html' === innerMode || 'xml' === innerMode ) { shouldAutocomplete = ( From 75173fded6a02b2aa8e8da7625e210aa51d61257 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Wed, 11 Feb 2026 23:34:31 -0800 Subject: [PATCH 21/52] Try alternative typedef Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index 6c9e558e37d0e..6f05d005dc798 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -346,21 +346,14 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { */ /** - * @typedef {Object} CodeMirrorEditor - * @property {import('codemirror').Doc} doc - Document. - * @property {CodeMirrorState} state - State. - * @property {CodeMirrorSettings} options - Options. - * @property {function(string):*} getOption - Get option. - * @property {function(string, *):void} setOption - Set option. - * @property {function(string, function):void} on - On event. - * @property {function(string, function):void} off - Off event. - * @property {function():void} [performLint] - Perform lint. - * @property {function(object):void} [showHint] - Show hint. - * @property {function():object} getMode - Get mode. - * @property {function():import('codemirror').Position} getCursor - Get cursor. - * @property {function(import('codemirror').Position):import('codemirror').Token} getTokenAt - Get token at. - * @property {function():HTMLElement} getWrapperElement - Get wrapper element. - * @property {function():HTMLTextAreaElement} getTextArea - Get text area. + * @typedef {import('codemirror').EditorFromTextArea & { + * performLint?: function(): void, + * showHint?: function(object): void, + * getOption(name: 'lint' | keyof import('codemirror').EditorConfiguration): any, + * setOption(name: 'lint' | keyof import('codemirror').EditorConfiguration, value: any): void, + * on(event: 'optionChange' | 'startCompletion' | 'endCompletion' | keyof import('codemirror').EditorEventMap, handler: function): void, + * off(event: 'optionChange' | 'startCompletion' | 'endCompletion' | keyof import('codemirror').EditorEventMap, handler: function): void + * }} CodeMirrorEditor */ /** From f5bcb810b7925e6d6bea6401209b1ae04dfd6ab5 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 18:43:22 -0800 Subject: [PATCH 22/52] Build Tooling: Introduce TypeScript checking for JavaScript files via JSDoc. Add a 'static-analysis:js' script to package.json that runs 'tsc'. Configure 'tsconfig.json' to check JSDoc in 'src/js/_enqueues/wp/code-editor.js' without emitting files, with settings mirrored from '.jshintrc'. Add global type definitions in 'typings/globals.d.ts' for 'wp', 'jQuery', '_', and 'Backbone'. Update 'src/js/_enqueues/wp/code-editor.js' to use global variables directly, satisfying both TypeScript and JSHint. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- package-lock.json | 33 ++++++++++++++++++++++++++++++ package.json | 3 +++ src/js/_enqueues/wp/code-editor.js | 8 ++++---- tsconfig.json | 30 +++++++++++++++++++++++++++ typings/globals.d.ts | 11 ++++++++++ 5 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 tsconfig.json create mode 100644 typings/globals.d.ts diff --git a/package-lock.json b/package-lock.json index dbccaa6b7c315..0a5e5cfce4838 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,6 +46,7 @@ "@playwright/test": "1.56.1", "@pmmmwh/react-refresh-webpack-plugin": "0.6.1", "@types/codemirror": "5.60.17", + "@types/jquery": "3.5.33", "@types/underscore": "1.11.15", "@wordpress/e2e-test-utils-playwright": "1.33.2", "@wordpress/prettier-config": "4.33.1", @@ -85,6 +86,7 @@ "sinon-test": "~3.1.6", "source-map-loader": "5.0.0", "terser-webpack-plugin": "5.3.14", + "typescript": "5.9.3", "uuid": "13.0.0", "wait-on": "9.0.3", "webpack": "5.98.0" @@ -5264,6 +5266,16 @@ "@types/istanbul-lib-report": "*" } }, + "node_modules/@types/jquery": { + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.33.tgz", + "integrity": "sha512-SeyVJXlCZpEki5F0ghuYe+L+PprQta6nRZqhONt9F13dWBtR/ftoaIbdRQ7cis7womE+X2LKhsDdDtkkDhJS6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/sizzle": "*" + } + }, "node_modules/@types/jsdom": { "version": "20.0.1", "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz", @@ -5418,6 +5430,13 @@ "@types/node": "*" } }, + "node_modules/@types/sizzle": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.10.tgz", + "integrity": "sha512-TC0dmN0K8YcWEAEfiPi5gJP14eJe30TTGjkvek3iM/1NdHHsdCA/Td6GvNndMOo/iSnIsZ4HuuhrYPDAmbxzww==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/sockjs": { "version": "0.3.36", "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", @@ -31209,6 +31228,20 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", diff --git a/package.json b/package.json index d14ceba1336ea..1c8fcc0ccc0e9 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "@playwright/test": "1.56.1", "@pmmmwh/react-refresh-webpack-plugin": "0.6.1", "@types/codemirror": "5.60.17", + "@types/jquery": "3.5.33", "@types/underscore": "1.11.15", "@wordpress/e2e-test-utils-playwright": "1.33.2", "@wordpress/prettier-config": "4.33.1", @@ -70,6 +71,7 @@ "sinon-test": "~3.1.6", "source-map-loader": "5.0.0", "terser-webpack-plugin": "5.3.14", + "typescript": "5.9.3", "uuid": "13.0.0", "wait-on": "9.0.3", "webpack": "5.98.0" @@ -116,6 +118,7 @@ "grunt": "grunt", "lint:jsdoc": "wp-scripts lint-js", "lint:jsdoc:fix": "wp-scripts lint-js --fix", + "static-analysis:js": "tsc", "env:start": "node ./tools/local-env/scripts/start.js && node ./tools/local-env/scripts/docker.js run -T --rm php composer update -W", "env:stop": "node ./tools/local-env/scripts/docker.js down", "env:restart": "npm run env:stop && npm run env:start", diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index 6f05d005dc798..c78cd3cae0e0a 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -4,17 +4,17 @@ /* eslint-env es2020 */ -if ( 'undefined' === typeof window.wp ) { +if ( 'undefined' === typeof wp ) { /** * @namespace wp */ window.wp = {}; } -if ( 'undefined' === typeof window.wp.codeEditor ) { +if ( 'undefined' === typeof wp.codeEditor ) { /** * @namespace wp.codeEditor */ - window.wp.codeEditor = {}; + wp.codeEditor = {}; } /** @@ -459,4 +459,4 @@ if ( 'undefined' === typeof window.wp.codeEditor ) { return instance; }; -})( window.jQuery, window.wp, window._ ); +})( jQuery, wp, _ ); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000000000..017276dd04a64 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "noEmit": true, + "module": "ESNext", + "target": "ES2020", + "moduleResolution": "node", + "strict": false, + "noImplicitAny": false, + "strictNullChecks": false, + "noUnusedLocals": true, + "noUnusedParameters": true, + "skipLibCheck": true, + "isolatedModules": true, + "lib": [ + "es2020", + "dom" + ], + "types": [ + "jquery", + "codemirror", + "underscore" + ] + }, + "include": [ + "src/js/_enqueues/wp/code-editor.js", + "typings/**/*.d.ts" + ] +} diff --git a/typings/globals.d.ts b/typings/globals.d.ts new file mode 100644 index 0000000000000..0172410947e25 --- /dev/null +++ b/typings/globals.d.ts @@ -0,0 +1,11 @@ +interface Window { + wp: any; + jQuery: any; + _: any; + Backbone: any; +} + +declare var wp: any; +declare var jQuery: any; +declare var _: any; +declare var Backbone: any; From c5e8db3ceca9d2408dcbc127562b08a74f53eea8 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 18:46:18 -0800 Subject: [PATCH 23/52] Code Editor: Refactor JSDoc types for TypeScript compatibility. Break down CodeEditorSettings into nested typedefs (CSSLintRules, JSHintRules, HTMLHintRules) to resolve parsing errors with dot notation in property names. Rename 'wp.codeEditor~CodeEditorInstance' to 'CodeEditorInstance' to resolve syntax errors caused by the '~' character. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 92 +++++++++++++++++------------- 1 file changed, 51 insertions(+), 41 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index c78cd3cae0e0a..acfc484ae6474 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -294,50 +294,60 @@ if ( 'undefined' === typeof wp.codeEditor ) { * }} CodeMirrorSettings */ + /** + * @typedef {object} CSSLintRules + * @property {boolean} [errors] - Errors. + * @property {boolean} [box-model] - Box model rules. + * @property {boolean} [display-property-grouping] - Display property grouping rules. + * @property {boolean} [duplicate-properties] - Duplicate properties rules. + * @property {boolean} [known-properties] - Known properties rules. + * @property {boolean} [outline-none] - Outline none rules. + */ + + /** + * @typedef {object} JSHintRules + * @property {number} [esversion] - ECMAScript version. + * @property {boolean} [module] - Whether to use modules. + * @property {boolean} [boss] - Whether to allow assignments in control expressions. + * @property {boolean} [curly] - Whether to require curly braces. + * @property {boolean} [eqeqeq] - Whether to require === and !==. + * @property {boolean} [eqnull] - Whether to allow == null. + * @property {boolean} [expr] - Whether to allow expressions. + * @property {boolean} [immed] - Whether to require immediate function invocation. + * @property {boolean} [noarg] - Whether to prohibit arguments.caller/callee. + * @property {boolean} [nonbsp] - Whether to prohibit non-breaking spaces. + * @property {string} [quotmark] - Quote mark preference. + * @property {boolean} [undef] - Whether to prohibit undefined variables. + * @property {boolean} [unused] - Whether to prohibit unused variables. + * @property {boolean} [browser] - Whether to enable browser globals. + * @property {Object} [globals] - Global variables. + */ + + /** + * @typedef {object} HTMLHintRules + * @property {boolean} [tagname-lowercase] - Tag name lowercase rules. + * @property {boolean} [attr-lowercase] - Attribute lowercase rules. + * @property {boolean} [attr-value-double-quotes] - Attribute value double quotes rules. + * @property {boolean} [doctype-first] - Doctype first rules. + * @property {boolean} [tag-pair] - Tag pair rules. + * @property {boolean} [spec-char-escape] - Spec char escape rules. + * @property {boolean} [id-unique] - ID unique rules. + * @property {boolean} [src-not-empty] - Src not empty rules. + * @property {boolean} [attr-no-duplication] - Attribute no duplication rules. + * @property {boolean} [alt-require] - Alt require rules. + * @property {string} [space-tab-mixed-disabled] - Space tab mixed disabled rules. + * @property {boolean} [attr-unsafe-chars] - Attribute unsafe chars rules. + */ + /** * Settings for the code editor. * * @typedef {object} CodeEditorSettings * * @property {CodeMirrorSettings} [codemirror] - CodeMirror settings. - * @property {object} [csslint] - CSSLint rules. - * @property {boolean} [csslint.errors] - Errors. - * @property {boolean} [csslint.box-model] - Box model rules. - * @property {boolean} [csslint.display-property-grouping] - Display property grouping rules. - * @property {boolean} [csslint.duplicate-properties] - Duplicate properties rules. - * @property {boolean} [csslint.known-properties] - Known properties rules. - * @property {boolean} [csslint.outline-none] - Outline none rules. - * - * @property {object} [jshint] - JSHint rules. - * @property {number} [jshint.esversion] - ECMAScript version. - * @property {boolean} [jshint.module] - Whether to use modules. - * @property {boolean} [jshint.boss] - Whether to allow assignments in control expressions. - * @property {boolean} [jshint.curly] - Whether to require curly braces. - * @property {boolean} [jshint.eqeqeq] - Whether to require === and !==. - * @property {boolean} [jshint.eqnull] - Whether to allow == null. - * @property {boolean} [jshint.expr] - Whether to allow expressions. - * @property {boolean} [jshint.immed] - Whether to require immediate function invocation. - * @property {boolean} [jshint.noarg] - Whether to prohibit arguments.caller/callee. - * @property {boolean} [jshint.nonbsp] - Whether to prohibit non-breaking spaces. - * @property {string} [jshint.quotmark] - Quote mark preference. - * @property {boolean} [jshint.undef] - Whether to prohibit undefined variables. - * @property {boolean} [jshint.unused] - Whether to prohibit unused variables. - * @property {boolean} [jshint.browser] - Whether to enable browser globals. - * @property {Object} [jshint.globals] - Global variables. - * - * @property {object} [htmlhint] - HTMLHint rules. - * @property {boolean} [htmlhint.tagname-lowercase] - Tag name lowercase rules. - * @property {boolean} [htmlhint.attr-lowercase] - Attribute lowercase rules. - * @property {boolean} [htmlhint.attr-value-double-quotes] - Attribute value double quotes rules. - * @property {boolean} [htmlhint.doctype-first] - Doctype first rules. - * @property {boolean} [htmlhint.tag-pair] - Tag pair rules. - * @property {boolean} [htmlhint.spec-char-escape] - Spec char escape rules. - * @property {boolean} [htmlhint.id-unique] - ID unique rules. - * @property {boolean} [htmlhint.src-not-empty] - Src not empty rules. - * @property {boolean} [htmlhint.attr-no-duplication] - Attribute no duplication rules. - * @property {boolean} [htmlhint.alt-require] - Alt require rules. - * @property {string} [htmlhint.space-tab-mixed-disabled] - Space tab mixed disabled rules. - * @property {boolean} [htmlhint.attr-unsafe-chars] - Attribute unsafe chars rules. + * @property {CSSLintRules} [csslint] - CSSLint rules. + * @property {JSHintRules} [jshint] - JSHint rules. + * @property {HTMLHintRules} [htmlhint] - HTMLHint rules. * * @property {Function} [onTabNext] - Callback to handle tabbing to the next tabbable element. * @property {Function} [onTabPrevious] - Callback to handle tabbing to the previous tabbable element. @@ -357,7 +367,7 @@ if ( 'undefined' === typeof wp.codeEditor ) { */ /** - * @typedef {object} wp.codeEditor~CodeEditorInstance + * @typedef {object} CodeEditorInstance * @property {CodeEditorSettings} settings - The code editor settings. * @property {CodeMirrorEditor} codemirror - The CodeMirror instance. * @property {Function} updateErrorNotice - Force update the error notice. @@ -371,7 +381,7 @@ if ( 'undefined' === typeof wp.codeEditor ) { * @param {string|jQuery|Element} textarea - The HTML id, jQuery object, or DOM Element for the textarea that is used for the editor. * @param {CodeEditorSettings} [settings] - Settings to override defaults. * - * @return {wp.codeEditor~CodeEditorInstance} Instance. + * @return {CodeEditorInstance} Instance. */ wp.codeEditor.initialize = function initialize( textarea, settings ) { let $textarea; @@ -389,7 +399,7 @@ if ( 'undefined' === typeof wp.codeEditor ) { const updateErrorNotice = configureLinting( codemirror, instanceSettings ); - /** @type {wp.codeEditor~CodeEditorInstance} */ + /** @type {CodeEditorInstance} */ const instance = { settings: instanceSettings, codemirror, From b4eda5b4a7d8c12de27f449a4428545f68f68fdc Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 18:48:04 -0800 Subject: [PATCH 24/52] Code Editor: Refine type definitions and resolve unused variable warnings. - Prefix unused variables '_cm' and '_editor' with an underscore to comply with 'noUnusedLocals' and 'noUnusedParameters'. - Remove the unused 'CodeMirrorState' typedef. - Add 'options' property to the 'CodeMirrorEditor' typedef to allow type-safe access to 'codemirror.options.mode'. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index acfc484ae6474..6c72c23f7920e 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -161,7 +161,7 @@ if ( 'undefined' === typeof wp.codeEditor ) { editor.setOption( 'lint', getLintOptions() ); // Keep lint options populated. - editor.on( 'optionChange', function( cm, option ) { + editor.on( 'optionChange', function( _cm, option ) { const gutterName = 'CodeMirror-lint-markers'; if ( 'lint' !== option ) { return; @@ -236,7 +236,7 @@ if ( 'undefined' === typeof wp.codeEditor ) { codemirror.on( 'blur', function() { $textarea.data( 'next-tab-blurs', false ); }); - codemirror.on( 'keydown', function onKeydown( editor, event ) { + codemirror.on( 'keydown', function onKeydown( _editor, event ) { // Take note of the ESC keypress so that the next TAB can focus outside the editor. if ( 'Escape' === event.key ) { $textarea.data( 'next-tab-blurs', true ); @@ -271,12 +271,6 @@ if ( 'undefined' === typeof wp.codeEditor ) { * @property {import('codemirror').Position} to - To position. */ - /** - * @typedef {object} CodeMirrorState - * @property {boolean} [completionActive] - Whether completion is active. - * @property {boolean} [focused] - Whether the editor is focused. - */ - /** * @typedef {object} CodeMirrorTokenState * @property {object} [htmlState] - HTML state. @@ -359,6 +353,7 @@ if ( 'undefined' === typeof wp.codeEditor ) { * @typedef {import('codemirror').EditorFromTextArea & { * performLint?: function(): void, * showHint?: function(object): void, + * options: import('codemirror').EditorConfiguration, * getOption(name: 'lint' | keyof import('codemirror').EditorConfiguration): any, * setOption(name: 'lint' | keyof import('codemirror').EditorConfiguration, value: any): void, * on(event: 'optionChange' | 'startCompletion' | 'endCompletion' | keyof import('codemirror').EditorEventMap, handler: function): void, @@ -407,7 +402,7 @@ if ( 'undefined' === typeof wp.codeEditor ) { }; if ( codemirror.showHint ) { - codemirror.on( 'inputRead', function( editor, change ) { + codemirror.on( 'inputRead', function( _editor, change ) { // Only trigger autocompletion for typed input or IME composition. if ( '+input' !== change.origin && ! change.origin.startsWith( '*compose' ) ) { return; From 835a3d9dbd5847f9211270dcba749e9dd9e11083 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 20:35:55 -0800 Subject: [PATCH 25/52] Code Editor: Simplify type casts in optionChange handler. - Replace 'any' with 'string[]' in the 'gutters' cast for better specificity. - Use a single direct cast for 'gutters' at declaration. - Change 'unknown' to 'string' in the 'option' cast for improved readability. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index 6c72c23f7920e..8492b2e0838c8 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -163,10 +163,10 @@ if ( 'undefined' === typeof wp.codeEditor ) { // Keep lint options populated. editor.on( 'optionChange', function( _cm, option ) { const gutterName = 'CodeMirror-lint-markers'; - if ( 'lint' !== option ) { + if ( 'lint' !== ( /** @type {string} */ ( option ) ) ) { return; } - const gutters = editor.getOption( 'gutters' ) || []; + const gutters = ( /** @type {string[]} */ ( editor.getOption( 'gutters' ) ) ) || []; const options = editor.getOption( 'lint' ); if ( true === options ) { if ( ! _.contains( gutters, gutterName ) ) { From 6cf7940ea2b30c78d69763c105cbddf432d43c90 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 20:37:31 -0800 Subject: [PATCH 26/52] Code Editor: Add explicit types for mousedown event handler. - Type 'event' as 'JQuery.MouseDownEvent' to resolve IDE warnings. - Cast 'event.target' to 'Node' and 'HTMLElement' for safe property access. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index 8492b2e0838c8..733dae9e0fdfe 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -213,8 +213,8 @@ if ( 'undefined' === typeof wp.codeEditor ) { * blurred the field and cause onUpdateErrorNotice to have already been * called. */ - $( document.body ).on( 'mousedown', function( event ) { - if ( editor.state.focused && ! editor.getWrapperElement().contains( event.target ) && ! event.target.classList.contains( 'CodeMirror-hint' ) ) { + $( document.body ).on( 'mousedown', function( /** @type {JQuery.MouseDownEvent} */ event ) { + if ( editor.state.focused && ! editor.getWrapperElement().contains( /** @type {Node} */ ( event.target ) ) && ! ( /** @type {HTMLElement} */ ( event.target ) ).classList.contains( 'CodeMirror-hint' ) ) { updateErrorNotice(); } }); From 1bad75487a5820d242258a2174b9890f5cd64927 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 20:41:54 -0800 Subject: [PATCH 27/52] Code Editor: Cast fromTextArea return value to CodeMirrorEditor. Resolve IDE and TypeScript assignment mismatch errors by explicitly casting the returned editor instance to the custom 'CodeMirrorEditor' type. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index 733dae9e0fdfe..44b669da4880b 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -389,8 +389,7 @@ if ( 'undefined' === typeof wp.codeEditor ) { /** @type {CodeEditorSettings} */ const instanceSettings = $.extend( true, {}, wp.codeEditor.defaultSettings, settings ); - /** @type {CodeMirrorEditor} */ - const codemirror = wp.CodeMirror.fromTextArea( $textarea[0], instanceSettings.codemirror ); + const codemirror = /** @type {CodeMirrorEditor} */ ( wp.CodeMirror.fromTextArea( $textarea[0], instanceSettings.codemirror ) ); const updateErrorNotice = configureLinting( codemirror, instanceSettings ); From b23615c691cda39417aafeec120be2ef27ebb5a2 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 20:59:40 -0800 Subject: [PATCH 28/52] Code Editor: Refine CodeMirror types and integrate addon definitions. - Integrate CodeMirror 'lint' and 'show-hint' addon types via triple-slash references in 'typings/globals.d.ts'. - Define 'CodeMirrorState' and refine 'CodeMirrorEditor' typedefs in 'code-editor.js' to provide better IDE resolution for 'completionActive', 'performLint', and 'showHint'. - Add a type cast in 'getLintOptions' for safe property access on the lint options object. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 17 ++++++++++------- typings/globals.d.ts | 3 +++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index 44b669da4880b..b2e2034e95b9b 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -73,7 +73,7 @@ if ( 'undefined' === typeof wp.codeEditor ) { * @return {Object} Lint options. */ function getLintOptions() { // eslint-disable-line complexity - let options = editor.getOption( 'lint' ); + let options = /** @type {any} */ ( editor.getOption( 'lint' ) ); if ( ! options ) { return false; @@ -349,15 +349,18 @@ if ( 'undefined' === typeof wp.codeEditor ) { * @property {Function} [onUpdateErrorNotice] - Callback for when error notice should be displayed. */ + /** + * @typedef {object} CodeMirrorState + * @property {boolean} [completionActive] - Whether completion is active. + * @property {boolean} [focused] - Whether the editor is focused. + */ + /** * @typedef {import('codemirror').EditorFromTextArea & { - * performLint?: function(): void, - * showHint?: function(object): void, * options: import('codemirror').EditorConfiguration, - * getOption(name: 'lint' | keyof import('codemirror').EditorConfiguration): any, - * setOption(name: 'lint' | keyof import('codemirror').EditorConfiguration, value: any): void, - * on(event: 'optionChange' | 'startCompletion' | 'endCompletion' | keyof import('codemirror').EditorEventMap, handler: function): void, - * off(event: 'optionChange' | 'startCompletion' | 'endCompletion' | keyof import('codemirror').EditorEventMap, handler: function): void + * performLint?: function(): void, + * showHint?: function(import('codemirror').ShowHintOptions): void, + * state: CodeMirrorState * }} CodeMirrorEditor */ diff --git a/typings/globals.d.ts b/typings/globals.d.ts index 0172410947e25..2ad5fac76825e 100644 --- a/typings/globals.d.ts +++ b/typings/globals.d.ts @@ -1,3 +1,6 @@ +/// +/// + interface Window { wp: any; jQuery: any; From dd7579f62c2733dc32b9b23e4d56ac462a0a83f2 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 21:19:38 -0800 Subject: [PATCH 29/52] Code Editor: Prevent redundant linting pass during initialization. Refactor 'configureLinting' to construct augmented lint options before CodeMirror initialization. Update 'wp.codeEditor.initialize' to pass these complete options directly to 'fromTextArea()', avoiding a subsequent 'setOption()' call that triggered a second linting pass and caused a race condition. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 170 ++++++++++++++++------------- 1 file changed, 97 insertions(+), 73 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index b2e2034e95b9b..a73d06093b202 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -46,21 +46,24 @@ if ( 'undefined' === typeof wp.codeEditor ) { /** * Configure linting. * - * @param {CodeMirrorEditor} editor - Editor. * @param {CodeEditorSettings} settings - Code editor settings. * - * @return {Function} Update error notice function. + * @return {Object} Linting controller. */ - function configureLinting( editor, settings ) { // eslint-disable-line complexity + function configureLinting( settings ) { // eslint-disable-line complexity + /** @type {LintAnnotation[]} */ let currentErrorAnnotations = []; + + /** @type {LintAnnotation[]} */ let previouslyShownErrorAnnotations = []; /** * Call the onUpdateErrorNotice if there are new errors to show. * + * @param {CodeMirrorEditor} editor - Editor. * @return {void} */ - function updateErrorNotice() { + function updateErrorNotice( editor ) { if ( settings.onUpdateErrorNotice && ! _.isEqual( currentErrorAnnotations, previouslyShownErrorAnnotations ) ) { settings.onUpdateErrorNotice( currentErrorAnnotations, editor ); previouslyShownErrorAnnotations = currentErrorAnnotations; @@ -70,10 +73,10 @@ if ( 'undefined' === typeof wp.codeEditor ) { /** * Get lint options. * - * @return {Object} Lint options. + * @return {Object|false} Lint options. */ function getLintOptions() { // eslint-disable-line complexity - let options = /** @type {any} */ ( editor.getOption( 'lint' ) ); + let options = settings.codemirror?.lint ?? false; if ( ! options ) { return false; @@ -95,17 +98,17 @@ if ( 'undefined' === typeof wp.codeEditor ) { } // Configure JSHint. - if ( 'javascript' === settings.codemirror.mode && settings.jshint ) { + if ( 'javascript' === settings.codemirror?.mode && settings.jshint ) { $.extend( options.options, settings.jshint ); } // Configure CSSLint. - if ( 'css' === settings.codemirror.mode && settings.csslint ) { + if ( 'css' === settings.codemirror?.mode && settings.csslint ) { $.extend( options.options, settings.csslint ); } // Configure HTMLHint. - if ( 'htmlmixed' === settings.codemirror.mode && settings.htmlhint ) { + if ( 'htmlmixed' === settings.codemirror?.mode && settings.htmlhint ) { options.options.rules = $.extend( {}, settings.htmlhint ); if ( settings.jshint ) { @@ -149,8 +152,8 @@ if ( 'undefined' === typeof wp.codeEditor ) { * were previously errors shown. In these cases, update immediately so they can know * that they fixed the errors. */ - if ( ! editor.state.focused || 0 === currentErrorAnnotations.length || previouslyShownErrorAnnotations.length > 0 ) { - updateErrorNotice(); + if ( ! cm.state.focused || 0 === currentErrorAnnotations.length || previouslyShownErrorAnnotations.length > 0 ) { + updateErrorNotice( cm ); } }; })( options.onUpdateLinting ); @@ -158,68 +161,82 @@ if ( 'undefined' === typeof wp.codeEditor ) { return options; } - editor.setOption( 'lint', getLintOptions() ); - - // Keep lint options populated. - editor.on( 'optionChange', function( _cm, option ) { - const gutterName = 'CodeMirror-lint-markers'; - if ( 'lint' !== ( /** @type {string} */ ( option ) ) ) { - return; - } - const gutters = ( /** @type {string[]} */ ( editor.getOption( 'gutters' ) ) ) || []; - const options = editor.getOption( 'lint' ); - if ( true === options ) { - if ( ! _.contains( gutters, gutterName ) ) { - editor.setOption( 'gutters', [ gutterName ].concat( gutters ) ); - } - editor.setOption( 'lint', getLintOptions() ); // Expand to include linting options. - } else if ( ! options ) { - editor.setOption( 'gutters', _.without( gutters, gutterName ) ); - } - - // Force update on error notice to show or hide. - if ( editor.getOption( 'lint' ) && editor.performLint ) { - editor.performLint(); - } else { - currentErrorAnnotations = []; - updateErrorNotice(); - } - } ); - - // Update error notice when leaving the editor. - editor.on( 'blur', updateErrorNotice ); - - // Work around hint selection with mouse causing focus to leave editor. - editor.on( 'startCompletion', function() { - editor.off( 'blur', updateErrorNotice ); - } ); - editor.on( 'endCompletion', function() { - const editorRefocusWait = 500; - editor.on( 'blur', updateErrorNotice ); - - // Wait for editor to possibly get re-focused after selection. - _.delay( function() { - if ( ! editor.state.focused ) { - updateErrorNotice(); - } - }, editorRefocusWait ); - }); + return { + getLintOptions, + /** + * @param {CodeMirrorEditor} editor - Editor instance. + * @return {void} + */ + init: function( editor ) { + // Keep lint options populated. + editor.on( 'optionChange', function( _cm, option ) { + const gutterName = 'CodeMirror-lint-markers'; + if ( 'lint' !== ( /** @type {string} */ ( option ) ) ) { + return; + } + const gutters = ( /** @type {string[]} */ ( editor.getOption( 'gutters' ) ) ) || []; + const options = editor.getOption( 'lint' ); + if ( true === options ) { + if ( ! _.contains( gutters, gutterName ) ) { + editor.setOption( 'gutters', [ gutterName ].concat( gutters ) ); + } + editor.setOption( 'lint', getLintOptions() ); // Expand to include linting options. + } else if ( ! options ) { + editor.setOption( 'gutters', _.without( gutters, gutterName ) ); + } - /* - * Make sure setting validities are set if the user tries to click Publish - * while an autocomplete dropdown is still open. The Customizer will block - * saving when a setting has an error notifications on it. This is only - * necessary for mouse interactions because keyboards will have already - * blurred the field and cause onUpdateErrorNotice to have already been - * called. - */ - $( document.body ).on( 'mousedown', function( /** @type {JQuery.MouseDownEvent} */ event ) { - if ( editor.state.focused && ! editor.getWrapperElement().contains( /** @type {Node} */ ( event.target ) ) && ! ( /** @type {HTMLElement} */ ( event.target ) ).classList.contains( 'CodeMirror-hint' ) ) { - updateErrorNotice(); - } - }); + // Force update on error notice to show or hide. + if ( editor.getOption( 'lint' ) && editor.performLint ) { + editor.performLint(); + } else { + currentErrorAnnotations = []; + updateErrorNotice( editor ); + } + } ); + + // Update error notice when leaving the editor. + editor.on( 'blur', function() { + updateErrorNotice( editor ); + } ); + + // Work around hint selection with mouse causing focus to leave editor. + editor.on( 'startCompletion', function() { + editor.off( 'blur', ( /** @type {any} */ ( updateErrorNotice ) ) ); + } ); + editor.on( 'endCompletion', function() { + const editorRefocusWait = 500; + editor.on( 'blur', function() { + updateErrorNotice( editor ); + } ); - return updateErrorNotice; + // Wait for editor to possibly get re-focused after selection. + _.delay( function() { + if ( ! editor.state.focused ) { + updateErrorNotice( editor ); + } + }, editorRefocusWait ); + } ); + + /* + * Make sure setting validities are set if the user tries to click Publish + * while an autocomplete dropdown is still open. The Customizer will block + * saving when a setting has an error notifications on it. This is only + * necessary for mouse interactions because keyboards will have already + * blurred the field and cause onUpdateErrorNotice to have already been + * called. + */ + $( document.body ).on( 'mousedown', function( /** @type {JQuery.MouseDownEvent} */ event ) { + if ( editor.state.focused && ! editor.getWrapperElement().contains( /** @type {Node} */ ( event.target ) ) && ! ( /** @type {HTMLElement} */ ( event.target ) ).classList.contains( 'CodeMirror-hint' ) ) { + updateErrorNotice( editor ); + } + } ); + }, + /** + * @param {CodeMirrorEditor} editor - Editor instance. + * @return {void} + */ + updateErrorNotice: updateErrorNotice + }; } /** @@ -392,15 +409,22 @@ if ( 'undefined' === typeof wp.codeEditor ) { /** @type {CodeEditorSettings} */ const instanceSettings = $.extend( true, {}, wp.codeEditor.defaultSettings, settings ); + const lintingController = configureLinting( instanceSettings ); + if ( instanceSettings.codemirror ) { + instanceSettings.codemirror.lint = lintingController.getLintOptions(); + } + const codemirror = /** @type {CodeMirrorEditor} */ ( wp.CodeMirror.fromTextArea( $textarea[0], instanceSettings.codemirror ) ); - const updateErrorNotice = configureLinting( codemirror, instanceSettings ); + lintingController.init( codemirror ); /** @type {CodeEditorInstance} */ const instance = { settings: instanceSettings, codemirror, - updateErrorNotice, + updateErrorNotice: function() { + lintingController.updateErrorNotice( codemirror ); + }, }; if ( codemirror.showHint ) { From 70e4196bf3afdf07990a6086423dac1405ca6ad7 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 21:25:43 -0800 Subject: [PATCH 30/52] Code Editor: Remove obsolete nested 'options.options' for linting. As of CodeMirror PR #4944, linter rules can be passed directly within the 'lint' option object alongside addon options like 'onUpdateLinting'. The addon now automatically separates them, making the nested 'options' property and the associated 'deprecated' comment obsolete. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index a73d06093b202..07e707a872137 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -88,34 +88,25 @@ if ( 'undefined' === typeof wp.codeEditor ) { options = $.extend( {}, options ); } - /* - * Note that rules must be sent in the "deprecated" lint.options property - * to prevent linter from complaining about unrecognized options. - * See . - */ - if ( ! options.options ) { - options.options = {}; - } - // Configure JSHint. if ( 'javascript' === settings.codemirror?.mode && settings.jshint ) { - $.extend( options.options, settings.jshint ); + $.extend( options, settings.jshint ); } // Configure CSSLint. if ( 'css' === settings.codemirror?.mode && settings.csslint ) { - $.extend( options.options, settings.csslint ); + $.extend( options, settings.csslint ); } // Configure HTMLHint. if ( 'htmlmixed' === settings.codemirror?.mode && settings.htmlhint ) { - options.options.rules = $.extend( {}, settings.htmlhint ); + options.rules = $.extend( {}, settings.htmlhint ); if ( settings.jshint ) { - options.options.rules.jshint = settings.jshint; + options.rules.jshint = settings.jshint; } if ( settings.csslint ) { - options.options.rules.csslint = settings.csslint; + options.rules.csslint = settings.csslint; } } From 9cbfb442702a7f24cbb39546dd8f6b0160a5dadd Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 21:50:25 -0800 Subject: [PATCH 31/52] Build Tooling: Reorganize CodeMirror source files. Move WordPress-specific CodeMirror extensions (fakejshint.js, htmlhint-kses.js, javascript-lint.js) from 'vendor/codemirror/' to 'lib/codemirror/'. Move 'esprima.js' to the 'vendor/' root and remove the now-empty 'vendor/codemirror/' directory. Update Grunt and Webpack configurations to reflect these source changes while preserving the existing build output structure in 'wp-includes/'. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- Gruntfile.js | 4 ++-- src/js/_enqueues/{vendor => lib}/codemirror/fakejshint.js | 0 src/js/_enqueues/{vendor => lib}/codemirror/htmlhint-kses.js | 0 .../_enqueues/{vendor => lib}/codemirror/javascript-lint.js | 0 src/js/_enqueues/vendor/{codemirror => }/esprima.js | 0 tools/vendors/codemirror-entry.js | 2 +- 6 files changed, 3 insertions(+), 3 deletions(-) rename src/js/_enqueues/{vendor => lib}/codemirror/fakejshint.js (100%) rename src/js/_enqueues/{vendor => lib}/codemirror/htmlhint-kses.js (100%) rename src/js/_enqueues/{vendor => lib}/codemirror/javascript-lint.js (100%) rename src/js/_enqueues/vendor/{codemirror => }/esprima.js (100%) diff --git a/Gruntfile.js b/Gruntfile.js index 9363a26a746a6..f86a7d994f492 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -334,13 +334,13 @@ module.exports = function(grunt) { files: [ { [ WORKING_DIR + 'wp-includes/js/codemirror/csslint.js' ]: [ './node_modules/csslint/dist/csslint.js' ], - [ WORKING_DIR + 'wp-includes/js/codemirror/esprima.js' ]: [ './node_modules/esprima/dist/esprima.js' ], + [ WORKING_DIR + 'wp-includes/js/codemirror/esprima.js' ]: [ './src/js/_enqueues/vendor/esprima.js' ], [ WORKING_DIR + 'wp-includes/js/codemirror/htmlhint.js' ]: [ './node_modules/htmlhint/dist/htmlhint.min.js' ], [ WORKING_DIR + 'wp-includes/js/codemirror/jsonlint.js' ]: [ './node_modules/jsonlint/web/jsonlint.js' ], }, { expand: true, - cwd: SOURCE_DIR + 'js/_enqueues/vendor/codemirror/', + cwd: SOURCE_DIR + 'js/_enqueues/lib/codemirror/', src: [ 'fakejshint.js', 'htmlhint-kses.js', diff --git a/src/js/_enqueues/vendor/codemirror/fakejshint.js b/src/js/_enqueues/lib/codemirror/fakejshint.js similarity index 100% rename from src/js/_enqueues/vendor/codemirror/fakejshint.js rename to src/js/_enqueues/lib/codemirror/fakejshint.js diff --git a/src/js/_enqueues/vendor/codemirror/htmlhint-kses.js b/src/js/_enqueues/lib/codemirror/htmlhint-kses.js similarity index 100% rename from src/js/_enqueues/vendor/codemirror/htmlhint-kses.js rename to src/js/_enqueues/lib/codemirror/htmlhint-kses.js diff --git a/src/js/_enqueues/vendor/codemirror/javascript-lint.js b/src/js/_enqueues/lib/codemirror/javascript-lint.js similarity index 100% rename from src/js/_enqueues/vendor/codemirror/javascript-lint.js rename to src/js/_enqueues/lib/codemirror/javascript-lint.js diff --git a/src/js/_enqueues/vendor/codemirror/esprima.js b/src/js/_enqueues/vendor/esprima.js similarity index 100% rename from src/js/_enqueues/vendor/codemirror/esprima.js rename to src/js/_enqueues/vendor/esprima.js diff --git a/tools/vendors/codemirror-entry.js b/tools/vendors/codemirror-entry.js index a8856f55d11da..7cb78ca6e9fb1 100644 --- a/tools/vendors/codemirror-entry.js +++ b/tools/vendors/codemirror-entry.js @@ -20,7 +20,7 @@ import 'codemirror/addon/lint/lint'; import 'codemirror/addon/lint/css-lint'; import 'codemirror/addon/lint/html-lint'; -import '../../src/js/_enqueues/vendor/codemirror/javascript-lint'; +import '../../src/js/_enqueues/lib/codemirror/javascript-lint'; import 'codemirror/addon/lint/json-lint'; // Addons (Other) From 8570258534825269b28a91a7c390344acfbc132f Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 22:10:54 -0800 Subject: [PATCH 32/52] Code Editor: Enable TypeScript checking for CodeMirror extensions. - Add 'javascript-lint.js' and 'htmlhint-kses.js' to 'tsconfig.json' include list. - Enable 'allowSyntheticDefaultImports' in 'tsconfig.json' for CodeMirror imports. - Add 'HTMLHint' global to 'typings/globals.d.ts'. - Install '@types/espree' for proper type definitions of the dynamically imported linter. - Refine 'SupportedJSHintOptions' and helper function JSDoc to use 'espree' types, ensuring strict type safety for 'ecmaVersion' without resorting to 'any'. - Add local '.eslintrc.json' to 'lib/codemirror/' to correctly signal ES module parsing for the IDE. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- package-lock.json | 25 +++++++++++++++++++ package.json | 1 + .../_enqueues/lib/codemirror/.eslintrc.json | 6 +++++ .../lib/codemirror/javascript-lint.js | 25 +++++++++++-------- tsconfig.json | 3 +++ typings/globals.d.ts | 2 ++ 6 files changed, 51 insertions(+), 11 deletions(-) create mode 100644 src/js/_enqueues/lib/codemirror/.eslintrc.json diff --git a/package-lock.json b/package-lock.json index 0a5e5cfce4838..f2b9896dcc141 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,6 +46,7 @@ "@playwright/test": "1.56.1", "@pmmmwh/react-refresh-webpack-plugin": "0.6.1", "@types/codemirror": "5.60.17", + "@types/espree": "10.1.0", "@types/jquery": "3.5.33", "@types/underscore": "1.11.15", "@wordpress/e2e-test-utils-playwright": "1.33.2", @@ -5187,6 +5188,30 @@ "@types/estree": "*" } }, + "node_modules/@types/espree": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@types/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-uPQZdoUWWMuO6WS8/dwX1stZH/vOBa/wAniGnYEFI0IuU9RmLx6PLmo+VGfNOlbRc5I7hBsQc8H0zcdVI37kxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.12.0", + "eslint-visitor-keys": "^4.0.0" + } + }, + "node_modules/@types/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", diff --git a/package.json b/package.json index 1c8fcc0ccc0e9..e69244c611d85 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "@playwright/test": "1.56.1", "@pmmmwh/react-refresh-webpack-plugin": "0.6.1", "@types/codemirror": "5.60.17", + "@types/espree": "10.1.0", "@types/jquery": "3.5.33", "@types/underscore": "1.11.15", "@wordpress/e2e-test-utils-playwright": "1.33.2", diff --git a/src/js/_enqueues/lib/codemirror/.eslintrc.json b/src/js/_enqueues/lib/codemirror/.eslintrc.json new file mode 100644 index 0000000000000..c3934091caa0f --- /dev/null +++ b/src/js/_enqueues/lib/codemirror/.eslintrc.json @@ -0,0 +1,6 @@ +{ + "parserOptions": { + "sourceType": "module", + "ecmaVersion": 2020 + } +} diff --git a/src/js/_enqueues/lib/codemirror/javascript-lint.js b/src/js/_enqueues/lib/codemirror/javascript-lint.js index 3f98ad523346c..592d077b80914 100644 --- a/src/js/_enqueues/lib/codemirror/javascript-lint.js +++ b/src/js/_enqueues/lib/codemirror/javascript-lint.js @@ -25,7 +25,7 @@ import CodeMirror from 'codemirror'; * @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 {import('espree').Options['ecmaVersion']} [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." @@ -50,19 +50,20 @@ async function validator( text, options ) { loc: true, } ); } catch ( error ) { + const enhancedError = /** @type {Error & { lineNumber?: number, column?: number }} */ ( error ); if ( // This is an `EnhancedSyntaxError` in Espree: . error instanceof SyntaxError && - typeof error.lineNumber === 'number' && - typeof error.column === 'number' + typeof enhancedError.lineNumber === 'number' && + typeof enhancedError.column === 'number' ) { - const line = error.lineNumber - 1; - errors.push( { + const line = enhancedError.lineNumber - 1; + errors.push( /** @type {CodeMirrorLintError} */ ( { message: error.message, severity: 'error', - from: CodeMirror.Pos( line, error.column - 1 ), - to: CodeMirror.Pos( line, error.column ), - } ); + from: CodeMirror.Pos( line, enhancedError.column - 1 ), + to: CodeMirror.Pos( line, enhancedError.column ), + } ) ); } else { console.warn( '[CodeMirror] Unable to lint JavaScript:', error ); // jshint ignore:line } @@ -80,13 +81,15 @@ CodeMirror.registerHelper( 'lint', 'javascript', validator ); * * @param {SupportedJSHintOptions} options - Linting options for JSHint. * @return {{ - * ecmaVersion?: number|'latest', + * ecmaVersion?: import('espree').Options['ecmaVersion'], + * sourceType?: 'module'|'script', * ecmaFeatures?: { * impliedStrict?: true * } * }} */ function getEspreeOptions( options ) { + /** @type {{ impliedStrict?: true }} */ const ecmaFeatures = {}; if ( options.strict === 'implied' ) { ecmaFeatures.impliedStrict = true; @@ -105,10 +108,10 @@ function getEspreeOptions( options ) { * @since 7.0.0 * * @param {SupportedJSHintOptions} options - Options. - * @return {number|'latest'} ECMAScript version. + * @return {import('espree').Options['ecmaVersion']} ECMAScript version. */ function getEcmaVersion( options ) { - if ( typeof options.esversion === 'number' ) { + if ( options.esversion ) { return options.esversion; } if ( options.es5 ) { diff --git a/tsconfig.json b/tsconfig.json index 017276dd04a64..d4e026790cfda 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,6 +13,7 @@ "noUnusedParameters": true, "skipLibCheck": true, "isolatedModules": true, + "allowSyntheticDefaultImports": true, "lib": [ "es2020", "dom" @@ -25,6 +26,8 @@ }, "include": [ "src/js/_enqueues/wp/code-editor.js", + "src/js/_enqueues/lib/codemirror/javascript-lint.js", + "src/js/_enqueues/lib/codemirror/htmlhint-kses.js", "typings/**/*.d.ts" ] } diff --git a/typings/globals.d.ts b/typings/globals.d.ts index 2ad5fac76825e..9604fc066bac0 100644 --- a/typings/globals.d.ts +++ b/typings/globals.d.ts @@ -6,9 +6,11 @@ interface Window { jQuery: any; _: any; Backbone: any; + HTMLHint: any; } declare var wp: any; declare var jQuery: any; declare var _: any; declare var Backbone: any; +declare var HTMLHint: any; From 26b7cee74df544b0431b119380ab30babd65a56f Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 22:14:55 -0800 Subject: [PATCH 33/52] Code Editor: Refactor htmlhint-kses.js to modern syntax. Use 'const' and 'let' for variable declarations and employ an arrow function for the 'tagstart' listener to simplify context handling and improve readability. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- .../_enqueues/lib/codemirror/htmlhint-kses.js | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/js/_enqueues/lib/codemirror/htmlhint-kses.js b/src/js/_enqueues/lib/codemirror/htmlhint-kses.js index 1aa7ffbd08cea..fce7d99a9811a 100644 --- a/src/js/_enqueues/lib/codemirror/htmlhint-kses.js +++ b/src/js/_enqueues/lib/codemirror/htmlhint-kses.js @@ -6,23 +6,20 @@ HTMLHint.addRule({ init: function( parser, reporter, options ) { 'use strict'; - var self = this; - parser.addListener( 'tagstart', function( event ) { - var attr, col, attrName, allowedAttributes, i, len, tagName; - - tagName = event.tagName.toLowerCase(); + parser.addListener( 'tagstart', ( event ) => { + const tagName = event.tagName.toLowerCase(); if ( ! options[ tagName ] ) { - reporter.error( 'Tag <' + event.tagName + '> is not allowed.', event.line, event.col, self, event.raw ); + reporter.error( 'Tag <' + event.tagName + '> is not allowed.', event.line, event.col, this, event.raw ); return; } - allowedAttributes = options[ tagName ]; - col = event.col + event.tagName.length + 1; - for ( i = 0, len = event.attrs.length; i < len; i++ ) { - attr = event.attrs[ i ]; - attrName = attr.name.toLowerCase(); + const allowedAttributes = options[ tagName ]; + const col = event.col + event.tagName.length + 1; + for ( let i = 0, len = event.attrs.length; i < len; i++ ) { + const attr = event.attrs[ i ]; + const attrName = attr.name.toLowerCase(); if ( ! allowedAttributes[ attrName ] ) { - reporter.error( 'Tag attribute [' + attr.raw + ' ] is not allowed.', event.line, col + attr.index, self, attr.raw ); + reporter.error( 'Tag attribute [' + attr.raw + ' ] is not allowed.', event.line, col + attr.index, this, attr.raw ); } } }); From 339fe05e86a8d3c5cc0e2a743453555aa72af470 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 22:15:46 -0800 Subject: [PATCH 34/52] Code Editor: Use for...of loop in htmlhint-kses.js. Refactor the attribute iteration to use a 'for...of' loop, improving code clarity and following modern JavaScript practices. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/lib/codemirror/htmlhint-kses.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/js/_enqueues/lib/codemirror/htmlhint-kses.js b/src/js/_enqueues/lib/codemirror/htmlhint-kses.js index fce7d99a9811a..00047ab11d04c 100644 --- a/src/js/_enqueues/lib/codemirror/htmlhint-kses.js +++ b/src/js/_enqueues/lib/codemirror/htmlhint-kses.js @@ -15,8 +15,7 @@ HTMLHint.addRule({ const allowedAttributes = options[ tagName ]; const col = event.col + event.tagName.length + 1; - for ( let i = 0, len = event.attrs.length; i < len; i++ ) { - const attr = event.attrs[ i ]; + for ( const attr of event.attrs ) { const attrName = attr.name.toLowerCase(); if ( ! allowedAttributes[ attrName ] ) { reporter.error( 'Tag attribute [' + attr.raw + ' ] is not allowed.', event.line, col + attr.index, this, attr.raw ); From 393b3601939c91f6ea34c30812c41bd512b7bff0 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 22:16:32 -0800 Subject: [PATCH 35/52] Code Editor: Use template literals in htmlhint-kses.js. Refactor the error reporting to use template literals for string interpolation, consistent with modern JavaScript standards. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/lib/codemirror/htmlhint-kses.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/_enqueues/lib/codemirror/htmlhint-kses.js b/src/js/_enqueues/lib/codemirror/htmlhint-kses.js index 00047ab11d04c..fd524a8c27444 100644 --- a/src/js/_enqueues/lib/codemirror/htmlhint-kses.js +++ b/src/js/_enqueues/lib/codemirror/htmlhint-kses.js @@ -9,7 +9,7 @@ HTMLHint.addRule({ parser.addListener( 'tagstart', ( event ) => { const tagName = event.tagName.toLowerCase(); if ( ! options[ tagName ] ) { - reporter.error( 'Tag <' + event.tagName + '> is not allowed.', event.line, event.col, this, event.raw ); + reporter.error( `Tag <${event.tagName}> is not allowed.`, event.line, event.col, this, event.raw ); return; } @@ -18,7 +18,7 @@ HTMLHint.addRule({ for ( const attr of event.attrs ) { const attrName = attr.name.toLowerCase(); if ( ! allowedAttributes[ attrName ] ) { - reporter.error( 'Tag attribute [' + attr.raw + ' ] is not allowed.', event.line, col + attr.index, this, attr.raw ); + reporter.error( `Tag attribute [${attr.raw}] is not allowed.`, event.line, col + attr.index, this, attr.raw ); } } }); From 6d5374a1a200373dac669a13d5276c74e03daeb2 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 22:19:46 -0800 Subject: [PATCH 36/52] Code Editor: Add HTMLHint types to htmlhint-kses.js. - Install '@types/htmlhint' to provide proper type definitions for HTML linter rules. - Update 'tsconfig.json' and 'typings/globals.d.ts' to use these types. - Add JSDoc annotations to 'htmlhint-kses.js' to eliminate implicit 'any' warnings and improve type safety. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++++++ package.json | 1 + src/js/_enqueues/lib/codemirror/htmlhint-kses.js | 9 +++++++++ tsconfig.json | 3 ++- typings/globals.d.ts | 4 ++-- 5 files changed, 22 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index f2b9896dcc141..c2b604ae017b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,6 +47,7 @@ "@pmmmwh/react-refresh-webpack-plugin": "0.6.1", "@types/codemirror": "5.60.17", "@types/espree": "10.1.0", + "@types/htmlhint": "1.1.5", "@types/jquery": "3.5.33", "@types/underscore": "1.11.15", "@wordpress/e2e-test-utils-playwright": "1.33.2", @@ -5252,6 +5253,13 @@ "@types/node": "*" } }, + "node_modules/@types/htmlhint": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@types/htmlhint/-/htmlhint-1.1.5.tgz", + "integrity": "sha512-BnMb05tZKcK0M/GK28H1jmCYRDqhmMUbxakbmmrBJ2vNpKPHLmAEWkq4UXdPN3cq3MDySZizhcbmYEg9i9G/QA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/http-errors": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", diff --git a/package.json b/package.json index e69244c611d85..7ef5bebb6394c 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "@pmmmwh/react-refresh-webpack-plugin": "0.6.1", "@types/codemirror": "5.60.17", "@types/espree": "10.1.0", + "@types/htmlhint": "1.1.5", "@types/jquery": "3.5.33", "@types/underscore": "1.11.15", "@wordpress/e2e-test-utils-playwright": "1.33.2", diff --git a/src/js/_enqueues/lib/codemirror/htmlhint-kses.js b/src/js/_enqueues/lib/codemirror/htmlhint-kses.js index fd524a8c27444..12c82f4c370c1 100644 --- a/src/js/_enqueues/lib/codemirror/htmlhint-kses.js +++ b/src/js/_enqueues/lib/codemirror/htmlhint-kses.js @@ -3,6 +3,15 @@ HTMLHint.addRule({ id: 'kses', description: 'Element or attribute cannot be used.', + /** + * Initialize. + * + * @this {import('htmlhint/types').Rule} + * @param {import('htmlhint').HTMLParser} parser - Parser. + * @param {import('htmlhint').Reporter} reporter - Reporter. + * @param {Record>} options - KSES options. + * @return {void} + */ init: function( parser, reporter, options ) { 'use strict'; diff --git a/tsconfig.json b/tsconfig.json index d4e026790cfda..602004a55edcc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -21,7 +21,8 @@ "types": [ "jquery", "codemirror", - "underscore" + "underscore", + "htmlhint" ] }, "include": [ diff --git a/typings/globals.d.ts b/typings/globals.d.ts index 9604fc066bac0..a588da28634dc 100644 --- a/typings/globals.d.ts +++ b/typings/globals.d.ts @@ -6,11 +6,11 @@ interface Window { jQuery: any; _: any; Backbone: any; - HTMLHint: any; + HTMLHint: typeof import('htmlhint').HTMLHint; } declare var wp: any; declare var jQuery: any; declare var _: any; declare var Backbone: any; -declare var HTMLHint: any; +declare var HTMLHint: typeof import('htmlhint').HTMLHint; From 493be25ba282f131bc110b227d2a9f6996943619 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 22:21:18 -0800 Subject: [PATCH 37/52] Eliminate abbreviated variables --- src/js/_enqueues/lib/codemirror/htmlhint-kses.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/js/_enqueues/lib/codemirror/htmlhint-kses.js b/src/js/_enqueues/lib/codemirror/htmlhint-kses.js index 12c82f4c370c1..669e06ad6289f 100644 --- a/src/js/_enqueues/lib/codemirror/htmlhint-kses.js +++ b/src/js/_enqueues/lib/codemirror/htmlhint-kses.js @@ -23,11 +23,10 @@ HTMLHint.addRule({ } const allowedAttributes = options[ tagName ]; - const col = event.col + event.tagName.length + 1; - for ( const attr of event.attrs ) { - const attrName = attr.name.toLowerCase(); - if ( ! allowedAttributes[ attrName ] ) { - reporter.error( `Tag attribute [${attr.raw}] is not allowed.`, event.line, col + attr.index, this, attr.raw ); + const column = event.col + event.tagName.length + 1; + for ( const attribute of event.attrs ) { + if ( ! allowedAttributes[ attribute.name.toLowerCase() ] ) { + reporter.error( `Tag attribute [${attribute.raw}] is not allowed.`, event.line, column + attribute.index, this, attribute.raw ); } } }); From b16bfaa4b5e3bfc24227774886f952927cfa5718 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 22:30:59 -0800 Subject: [PATCH 38/52] Code Editor: Strengthen TypeScript checking with specific JSDoc types. - Define 'WpCodeEditor', 'CodeEditorInstance', and 'LintingController' typedefs to replace generic 'Object' and 'Function' types. - Move all typedefs to the top of the file to ensure they are properly recognized by the TypeScript compiler and to resolve 'unused' warnings. - Use specific CodeMirror addon types for linting options. - Refine function signatures with detailed parameter and return type information. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 258 ++++++++++++++++------------- 1 file changed, 140 insertions(+), 118 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index 07e707a872137..0533b5a4eb802 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -17,10 +17,128 @@ if ( 'undefined' === typeof wp.codeEditor ) { wp.codeEditor = {}; } +/** + * @typedef {object} CodeMirrorState + * @property {boolean} [completionActive] - Whether completion is active. + * @property {boolean} [focused] - Whether the editor is focused. + */ + +/** + * @typedef {import('codemirror').EditorFromTextArea & { + * options: import('codemirror').EditorConfiguration, + * performLint?: () => void, + * showHint?: (options: import('codemirror').ShowHintOptions) => void, + * state: CodeMirrorState + * }} CodeMirrorEditor + */ + +/** + * @typedef {object} LintAnnotation + * @property {string} message - Message. + * @property {'error'|'warning'} severity - Severity. + * @property {import('codemirror').Position} from - From position. + * @property {import('codemirror').Position} to - To position. + */ + +/** + * @typedef {object} CodeMirrorTokenState + * @property {object} [htmlState] - HTML state. + * @property {string} [htmlState.tagName] - Tag name. + * @property {CodeMirrorTokenState} [curState] - Current state. + */ + +/** + * @typedef {import('codemirror').EditorConfiguration & { + * lint?: boolean | import('codemirror/addon/lint/lint').Linter, + * autoCloseBrackets?: boolean, + * matchBrackets?: boolean, + * continueComments?: boolean, + * styleActiveLine?: boolean + * }} CodeMirrorSettings + */ + +/** + * @typedef {object} CSSLintRules + * @property {boolean} [errors] - Errors. + * @property {boolean} [box-model] - Box model rules. + * @property {boolean} [display-property-grouping] - Display property grouping rules. + * @property {boolean} [duplicate-properties] - Duplicate properties rules. + * @property {boolean} [known-properties] - Known properties rules. + * @property {boolean} [outline-none] - Outline none rules. + */ + +/** + * @typedef {object} JSHintRules + * @property {number} [esversion] - ECMAScript version. + * @property {boolean} [module] - Whether to use modules. + * @property {boolean} [boss] - Whether to allow assignments in control expressions. + * @property {boolean} [curly] - Whether to require curly braces. + * @property {boolean} [eqeqeq] - Whether to require === and !==. + * @property {boolean} [eqnull] - Whether to allow == null. + * @property {boolean} [expr] - Whether to allow expressions. + * @property {boolean} [immed] - Whether to require immediate function invocation. + * @property {boolean} [noarg] - Whether to prohibit arguments.caller/callee. + * @property {boolean} [nonbsp] - Whether to prohibit non-breaking spaces. + * @property {string} [quotmark] - Quote mark preference. + * @property {boolean} [undef] - Whether to prohibit undefined variables. + * @property {boolean} [unused] - Whether to prohibit unused variables. + * @property {boolean} [browser] - Whether to enable browser globals. + * @property {Object} [globals] - Global variables. + */ + +/** + * @typedef {object} HTMLHintRules + * @property {boolean} [tagname-lowercase] - Tag name lowercase rules. + * @property {boolean} [attr-lowercase] - Attribute lowercase rules. + * @property {boolean} [attr-value-double-quotes] - Attribute value double quotes rules. + * @property {boolean} [doctype-first] - Doctype first rules. + * @property {boolean} [tag-pair] - Tag pair rules. + * @property {boolean} [spec-char-escape] - Spec char escape rules. + * @property {boolean} [id-unique] - ID unique rules. + * @property {boolean} [src-not-empty] - Src not empty rules. + * @property {boolean} [attr-no-duplication] - Attribute no duplication rules. + * @property {boolean} [alt-require] - Alt require rules. + * @property {string} [space-tab-mixed-disabled] - Space tab mixed disabled rules. + * @property {boolean} [attr-unsafe-chars] - Attribute unsafe chars rules. + * @property {JSHintRules} [jshint] - JSHint rules. + * @property {CSSLintRules} [csslint] - CSSLint rules. + */ + +/** + * Settings for the code editor. + * + * @typedef {object} CodeEditorSettings + * + * @property {CodeMirrorSettings} [codemirror] - CodeMirror settings. + * @property {CSSLintRules} [csslint] - CSSLint rules. + * @property {JSHintRules} [jshint] - JSHint rules. + * @property {HTMLHintRules} [htmlhint] - HTMLHint rules. + * + * @property {(codemirror: CodeMirrorEditor, event: KeyboardEvent|JQuery.KeyDownEvent) => void} [onTabNext] - Callback to handle tabbing to the next tabbable element. + * @property {(codemirror: CodeMirrorEditor, event: KeyboardEvent|JQuery.KeyDownEvent) => void} [onTabPrevious] - Callback to handle tabbing to the previous tabbable element. + * @property {(errorAnnotations: LintAnnotation[], annotations: LintAnnotation[], annotationsSorted: LintAnnotation[], cm: CodeMirrorEditor) => void} [onChangeLintingErrors] - Callback for when the linting errors have changed. + * @property {(errorAnnotations: LintAnnotation[], editor: CodeMirrorEditor) => void} [onUpdateErrorNotice] - Callback for when error notice should be displayed. + */ + +/** + * @typedef {object} CodeEditorInstance + * @property {CodeEditorSettings} settings - The code editor settings. + * @property {CodeMirrorEditor} codemirror - The CodeMirror instance. + * @property {() => void} updateErrorNotice - Force update the error notice. + */ + +/** + * @typedef {object} WpCodeEditor + * @property {CodeEditorSettings} defaultSettings - Default settings. + * @property {(textarea: string|jQuery|Element, settings?: CodeEditorSettings) => CodeEditorInstance} initialize - Initialize. + */ + /** * @param {jQuery} $ - jQuery. - * @param {Object} wp - WordPress namespace. - * @param {import('codemirror')} wp.CodeMirror - CodeMirror. + * @param {Object & { + * codeEditor: WpCodeEditor, + * CodeMirror: typeof import('codemirror'), + * }} wp - WordPress namespace. * @param {import('underscore').UnderscoreStatic} _ - Underscore. */ ( function( $, wp, _ ) { @@ -48,7 +166,7 @@ if ( 'undefined' === typeof wp.codeEditor ) { * * @param {CodeEditorSettings} settings - Code editor settings. * - * @return {Object} Linting controller. + * @return {LintingController} Linting controller. */ function configureLinting( settings ) { // eslint-disable-line complexity /** @type {LintAnnotation[]} */ @@ -73,9 +191,10 @@ if ( 'undefined' === typeof wp.codeEditor ) { /** * Get lint options. * - * @return {Object|false} Lint options. + * @return {import('codemirror/addon/lint/lint').Linter|false} Lint options. */ function getLintOptions() { // eslint-disable-line complexity + /** @type {import('codemirror/addon/lint/lint').Linter | boolean} */ let options = settings.codemirror?.lint ?? false; if ( ! options ) { @@ -83,35 +202,39 @@ if ( 'undefined' === typeof wp.codeEditor ) { } if ( true === options ) { - options = {}; + options = { + // @ts-ignore + rules: {} + }; } else if ( _.isObject( options ) ) { options = $.extend( {}, options ); } + const linterOptions = /** @type {import('codemirror/addon/lint/lint').Linter & { rules?: any, onUpdateLinting?: Function }} */ ( options ); // Configure JSHint. if ( 'javascript' === settings.codemirror?.mode && settings.jshint ) { - $.extend( options, settings.jshint ); + $.extend( linterOptions, settings.jshint ); } // Configure CSSLint. if ( 'css' === settings.codemirror?.mode && settings.csslint ) { - $.extend( options, settings.csslint ); + $.extend( linterOptions, settings.csslint ); } // Configure HTMLHint. if ( 'htmlmixed' === settings.codemirror?.mode && settings.htmlhint ) { - options.rules = $.extend( {}, settings.htmlhint ); + linterOptions.rules = $.extend( {}, settings.htmlhint ); if ( settings.jshint ) { - options.rules.jshint = settings.jshint; + linterOptions.rules.jshint = settings.jshint; } if ( settings.csslint ) { - options.rules.csslint = settings.csslint; + linterOptions.rules.csslint = settings.csslint; } } // Wrap the onUpdateLinting CodeMirror event to route to onChangeLintingErrors and onUpdateErrorNotice. - options.onUpdateLinting = (function( onUpdateLintingOverridden ) { + linterOptions.onUpdateLinting = (function( onUpdateLintingOverridden ) { /** * @param {LintAnnotation[]} annotations - Annotations. * @param {LintAnnotation[]} annotationsSorted - Sorted annotations. @@ -147,9 +270,9 @@ if ( 'undefined' === typeof wp.codeEditor ) { updateErrorNotice( cm ); } }; - })( options.onUpdateLinting ); + })( linterOptions.onUpdateLinting ); - return options; + return linterOptions; } return { @@ -272,111 +395,10 @@ if ( 'undefined' === typeof wp.codeEditor ) { } /** - * @typedef {object} LintAnnotation - * @property {string} message - Message. - * @property {'error'|'warning'} severity - Severity. - * @property {import('codemirror').Position} from - From position. - * @property {import('codemirror').Position} to - To position. - */ - - /** - * @typedef {object} CodeMirrorTokenState - * @property {object} [htmlState] - HTML state. - * @property {string} [htmlState.tagName] - Tag name. - * @property {CodeMirrorTokenState} [curState] - Current state. - */ - - /** - * @typedef {import('codemirror').EditorConfiguration & { - * lint?: boolean | object, - * autoCloseBrackets?: boolean, - * matchBrackets?: boolean, - * continueComments?: boolean, - * styleActiveLine?: boolean - * }} CodeMirrorSettings - */ - - /** - * @typedef {object} CSSLintRules - * @property {boolean} [errors] - Errors. - * @property {boolean} [box-model] - Box model rules. - * @property {boolean} [display-property-grouping] - Display property grouping rules. - * @property {boolean} [duplicate-properties] - Duplicate properties rules. - * @property {boolean} [known-properties] - Known properties rules. - * @property {boolean} [outline-none] - Outline none rules. - */ - - /** - * @typedef {object} JSHintRules - * @property {number} [esversion] - ECMAScript version. - * @property {boolean} [module] - Whether to use modules. - * @property {boolean} [boss] - Whether to allow assignments in control expressions. - * @property {boolean} [curly] - Whether to require curly braces. - * @property {boolean} [eqeqeq] - Whether to require === and !==. - * @property {boolean} [eqnull] - Whether to allow == null. - * @property {boolean} [expr] - Whether to allow expressions. - * @property {boolean} [immed] - Whether to require immediate function invocation. - * @property {boolean} [noarg] - Whether to prohibit arguments.caller/callee. - * @property {boolean} [nonbsp] - Whether to prohibit non-breaking spaces. - * @property {string} [quotmark] - Quote mark preference. - * @property {boolean} [undef] - Whether to prohibit undefined variables. - * @property {boolean} [unused] - Whether to prohibit unused variables. - * @property {boolean} [browser] - Whether to enable browser globals. - * @property {Object} [globals] - Global variables. - */ - - /** - * @typedef {object} HTMLHintRules - * @property {boolean} [tagname-lowercase] - Tag name lowercase rules. - * @property {boolean} [attr-lowercase] - Attribute lowercase rules. - * @property {boolean} [attr-value-double-quotes] - Attribute value double quotes rules. - * @property {boolean} [doctype-first] - Doctype first rules. - * @property {boolean} [tag-pair] - Tag pair rules. - * @property {boolean} [spec-char-escape] - Spec char escape rules. - * @property {boolean} [id-unique] - ID unique rules. - * @property {boolean} [src-not-empty] - Src not empty rules. - * @property {boolean} [attr-no-duplication] - Attribute no duplication rules. - * @property {boolean} [alt-require] - Alt require rules. - * @property {string} [space-tab-mixed-disabled] - Space tab mixed disabled rules. - * @property {boolean} [attr-unsafe-chars] - Attribute unsafe chars rules. - */ - - /** - * Settings for the code editor. - * - * @typedef {object} CodeEditorSettings - * - * @property {CodeMirrorSettings} [codemirror] - CodeMirror settings. - * @property {CSSLintRules} [csslint] - CSSLint rules. - * @property {JSHintRules} [jshint] - JSHint rules. - * @property {HTMLHintRules} [htmlhint] - HTMLHint rules. - * - * @property {Function} [onTabNext] - Callback to handle tabbing to the next tabbable element. - * @property {Function} [onTabPrevious] - Callback to handle tabbing to the previous tabbable element. - * @property {Function} [onChangeLintingErrors] - Callback for when the linting errors have changed. - * @property {Function} [onUpdateErrorNotice] - Callback for when error notice should be displayed. - */ - - /** - * @typedef {object} CodeMirrorState - * @property {boolean} [completionActive] - Whether completion is active. - * @property {boolean} [focused] - Whether the editor is focused. - */ - - /** - * @typedef {import('codemirror').EditorFromTextArea & { - * options: import('codemirror').EditorConfiguration, - * performLint?: function(): void, - * showHint?: function(import('codemirror').ShowHintOptions): void, - * state: CodeMirrorState - * }} CodeMirrorEditor - */ - - /** - * @typedef {object} CodeEditorInstance - * @property {CodeEditorSettings} settings - The code editor settings. - * @property {CodeMirrorEditor} codemirror - The CodeMirror instance. - * @property {Function} updateErrorNotice - Force update the error notice. + * @typedef {object} LintingController + * @property {() => import('codemirror/addon/lint/lint').Linter|false} getLintOptions - Get lint options. + * @property {(editor: CodeMirrorEditor) => void} init - Initialize. + * @property {(editor: CodeMirrorEditor) => void} updateErrorNotice - Update error notice. */ /** From c8a795a560d0a7cee1856bc67a1bde7f6a75875b Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 22:35:04 -0800 Subject: [PATCH 39/52] Code Editor: Enable strict TypeScript checking. - Set 'strict: true' in 'tsconfig.json'. - Add required '' type arguments to 'Linter' generic type references in 'code-editor.js'. - Implement null checks for 'onTabPrevious', 'onTabNext', and 'change.origin' in 'code-editor.js'. - Pass 'instanceSettings' to 'configureTabbing' to ensure settings are always defined. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 18 +++++++++--------- tsconfig.json | 4 +--- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index 0533b5a4eb802..2d4060d29db42 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -49,7 +49,7 @@ if ( 'undefined' === typeof wp.codeEditor ) { /** * @typedef {import('codemirror').EditorConfiguration & { - * lint?: boolean | import('codemirror/addon/lint/lint').Linter, + * lint?: boolean | import('codemirror/addon/lint/lint').Linter, * autoCloseBrackets?: boolean, * matchBrackets?: boolean, * continueComments?: boolean, @@ -191,10 +191,10 @@ if ( 'undefined' === typeof wp.codeEditor ) { /** * Get lint options. * - * @return {import('codemirror/addon/lint/lint').Linter|false} Lint options. + * @return {import('codemirror/addon/lint/lint').Linter|false} Lint options. */ function getLintOptions() { // eslint-disable-line complexity - /** @type {import('codemirror/addon/lint/lint').Linter | boolean} */ + /** @type {import('codemirror/addon/lint/lint').Linter | boolean} */ let options = settings.codemirror?.lint ?? false; if ( ! options ) { @@ -209,7 +209,7 @@ if ( 'undefined' === typeof wp.codeEditor ) { } else if ( _.isObject( options ) ) { options = $.extend( {}, options ); } - const linterOptions = /** @type {import('codemirror/addon/lint/lint').Linter & { rules?: any, onUpdateLinting?: Function }} */ ( options ); + const linterOptions = /** @type {import('codemirror/addon/lint/lint').Linter & { rules?: any, onUpdateLinting?: Function }} */ ( options ); // Configure JSHint. if ( 'javascript' === settings.codemirror?.mode && settings.jshint ) { @@ -380,9 +380,9 @@ if ( 'undefined' === typeof wp.codeEditor ) { } // Focus on previous or next focusable item. - if ( event.shiftKey ) { + if ( event.shiftKey && settings.onTabPrevious ) { settings.onTabPrevious( codemirror, event ); - } else { + } else if ( ! event.shiftKey && settings.onTabNext ) { settings.onTabNext( codemirror, event ); } @@ -396,7 +396,7 @@ if ( 'undefined' === typeof wp.codeEditor ) { /** * @typedef {object} LintingController - * @property {() => import('codemirror/addon/lint/lint').Linter|false} getLintOptions - Get lint options. + * @property {() => import('codemirror/addon/lint/lint').Linter|false} getLintOptions - Get lint options. * @property {(editor: CodeMirrorEditor) => void} init - Initialize. * @property {(editor: CodeMirrorEditor) => void} updateErrorNotice - Update error notice. */ @@ -443,7 +443,7 @@ if ( 'undefined' === typeof wp.codeEditor ) { if ( codemirror.showHint ) { codemirror.on( 'inputRead', function( _editor, change ) { // Only trigger autocompletion for typed input or IME composition. - if ( '+input' !== change.origin && ! change.origin.startsWith( '*compose' ) ) { + if ( ! change.origin || ( '+input' !== change.origin && ! change.origin.startsWith( '*compose' ) ) ) { return; } @@ -498,7 +498,7 @@ if ( 'undefined' === typeof wp.codeEditor ) { } // Facilitate tabbing out of the editor. - configureTabbing( codemirror, settings ); + configureTabbing( codemirror, instanceSettings ); return instance; }; diff --git a/tsconfig.json b/tsconfig.json index 602004a55edcc..7c8f1c213f8bf 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,9 +6,7 @@ "module": "ESNext", "target": "ES2020", "moduleResolution": "node", - "strict": false, - "noImplicitAny": false, - "strictNullChecks": false, + "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, "skipLibCheck": true, From 6fe9a8edafa0ab63324f9418efa0ff5616c8773c Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 22:38:30 -0800 Subject: [PATCH 40/52] Code Editor: Refine linting types and reduce 'any' usage. - Replace 'Linter' with 'LintStateOptions' in typedefs and return types to correctly match CodeMirror's addon configuration structure. - Refine the 'linterOptions' cast to use a specific union of rules types ('CSSLintRules | JSHintRules | HTMLHintRules') instead of 'any'. - Update 'getLintOptions' logic to use 'linterOptions.options' for rule assignment, consistent with modern CodeMirror practices. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index 2d4060d29db42..cdb166d2bd749 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -49,7 +49,7 @@ if ( 'undefined' === typeof wp.codeEditor ) { /** * @typedef {import('codemirror').EditorConfiguration & { - * lint?: boolean | import('codemirror/addon/lint/lint').Linter, + * lint?: boolean | import('codemirror/addon/lint/lint').LintStateOptions, * autoCloseBrackets?: boolean, * matchBrackets?: boolean, * continueComments?: boolean, @@ -191,10 +191,10 @@ if ( 'undefined' === typeof wp.codeEditor ) { /** * Get lint options. * - * @return {import('codemirror/addon/lint/lint').Linter|false} Lint options. + * @return {import('codemirror/addon/lint/lint').LintStateOptions|false} Lint options. */ function getLintOptions() { // eslint-disable-line complexity - /** @type {import('codemirror/addon/lint/lint').Linter | boolean} */ + /** @type {import('codemirror/addon/lint/lint').LintStateOptions | boolean} */ let options = settings.codemirror?.lint ?? false; if ( ! options ) { @@ -203,33 +203,33 @@ if ( 'undefined' === typeof wp.codeEditor ) { if ( true === options ) { options = { - // @ts-ignore - rules: {} + options: {} }; } else if ( _.isObject( options ) ) { options = $.extend( {}, options ); } - const linterOptions = /** @type {import('codemirror/addon/lint/lint').Linter & { rules?: any, onUpdateLinting?: Function }} */ ( options ); + const linterOptions = /** @type {import('codemirror/addon/lint/lint').LintStateOptions} */ ( options ); // Configure JSHint. if ( 'javascript' === settings.codemirror?.mode && settings.jshint ) { - $.extend( linterOptions, settings.jshint ); + linterOptions.options = $.extend( linterOptions.options || {}, settings.jshint ); } // Configure CSSLint. if ( 'css' === settings.codemirror?.mode && settings.csslint ) { - $.extend( linterOptions, settings.csslint ); + linterOptions.options = $.extend( linterOptions.options || {}, settings.csslint ); } // Configure HTMLHint. if ( 'htmlmixed' === settings.codemirror?.mode && settings.htmlhint ) { - linterOptions.rules = $.extend( {}, settings.htmlhint ); + linterOptions.options = $.extend( linterOptions.options || {}, settings.htmlhint ); + const rules = /** @type {HTMLHintRules} */ ( linterOptions.options ); if ( settings.jshint ) { - linterOptions.rules.jshint = settings.jshint; + rules.jshint = settings.jshint; } if ( settings.csslint ) { - linterOptions.rules.csslint = settings.csslint; + rules.csslint = settings.csslint; } } @@ -396,7 +396,7 @@ if ( 'undefined' === typeof wp.codeEditor ) { /** * @typedef {object} LintingController - * @property {() => import('codemirror/addon/lint/lint').Linter|false} getLintOptions - Get lint options. + * @property {() => import('codemirror/addon/lint/lint').LintStateOptions|false} getLintOptions - Get lint options. * @property {(editor: CodeMirrorEditor) => void} init - Initialize. * @property {(editor: CodeMirrorEditor) => void} updateErrorNotice - Update error notice. */ From 6489ad05e587231f1c0c157bbd3330a113dc1cfb Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 22:41:40 -0800 Subject: [PATCH 41/52] Code Editor: Use flat linting options and refine intersection type. - Remove the redundant 'options.options' nesting in 'getLintOptions', following modern CodeMirror practices (PR 4944). - Use a comprehensive intersection type for 'linterOptions' that includes 'LintStateOptions', rule unions, and an explicit 'rules' property to satisfy the TypeScript compiler in strict mode. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index cdb166d2bd749..0c18bf6cc7da8 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -202,34 +202,31 @@ if ( 'undefined' === typeof wp.codeEditor ) { } if ( true === options ) { - options = { - options: {} - }; + options = {}; } else if ( _.isObject( options ) ) { options = $.extend( {}, options ); } - const linterOptions = /** @type {import('codemirror/addon/lint/lint').LintStateOptions} */ ( options ); + const linterOptions = /** @type {import('codemirror/addon/lint/lint').LintStateOptions & (CSSLintRules | JSHintRules | HTMLHintRules) & { rules?: any }} */ ( options ); // Configure JSHint. if ( 'javascript' === settings.codemirror?.mode && settings.jshint ) { - linterOptions.options = $.extend( linterOptions.options || {}, settings.jshint ); + $.extend( linterOptions, settings.jshint ); } // Configure CSSLint. if ( 'css' === settings.codemirror?.mode && settings.csslint ) { - linterOptions.options = $.extend( linterOptions.options || {}, settings.csslint ); + $.extend( linterOptions, settings.csslint ); } // Configure HTMLHint. if ( 'htmlmixed' === settings.codemirror?.mode && settings.htmlhint ) { - linterOptions.options = $.extend( linterOptions.options || {}, settings.htmlhint ); + linterOptions.rules = $.extend( {}, settings.htmlhint ); - const rules = /** @type {HTMLHintRules} */ ( linterOptions.options ); if ( settings.jshint ) { - rules.jshint = settings.jshint; + linterOptions.rules.jshint = settings.jshint; } if ( settings.csslint ) { - rules.csslint = settings.csslint; + linterOptions.rules.csslint = settings.csslint; } } From 6a94d99773e8e32334d6b4095a9a2931459db05e Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 22:45:20 -0800 Subject: [PATCH 42/52] Code Editor: Refine linting types and eliminate 'any' usage. - Define 'CombinedLintOptions' intersection type to precisely model the flat options structure, including standard CodeMirror lint options and specific linter rules. - Replace generic 'any' types with 'CombinedLintOptions' in typedefs and return types. - Add defensive checks when configuring HTMLHint rules to satisfy strict null checking. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index 0c18bf6cc7da8..768864af19d84 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -49,7 +49,7 @@ if ( 'undefined' === typeof wp.codeEditor ) { /** * @typedef {import('codemirror').EditorConfiguration & { - * lint?: boolean | import('codemirror/addon/lint/lint').LintStateOptions, + * lint?: boolean | CombinedLintOptions, * autoCloseBrackets?: boolean, * matchBrackets?: boolean, * continueComments?: boolean, @@ -120,6 +120,10 @@ if ( 'undefined' === typeof wp.codeEditor ) { * @property {(errorAnnotations: LintAnnotation[], editor: CodeMirrorEditor) => void} [onUpdateErrorNotice] - Callback for when error notice should be displayed. */ +/** + * @typedef {import('codemirror/addon/lint/lint').LintStateOptions> & JSHintRules & CSSLintRules & { rules?: HTMLHintRules }} CombinedLintOptions + */ + /** * @typedef {object} CodeEditorInstance * @property {CodeEditorSettings} settings - The code editor settings. @@ -191,10 +195,10 @@ if ( 'undefined' === typeof wp.codeEditor ) { /** * Get lint options. * - * @return {import('codemirror/addon/lint/lint').LintStateOptions|false} Lint options. + * @return {CombinedLintOptions|false} Lint options. */ function getLintOptions() { // eslint-disable-line complexity - /** @type {import('codemirror/addon/lint/lint').LintStateOptions | boolean} */ + /** @type {CombinedLintOptions | boolean} */ let options = settings.codemirror?.lint ?? false; if ( ! options ) { @@ -206,7 +210,7 @@ if ( 'undefined' === typeof wp.codeEditor ) { } else if ( _.isObject( options ) ) { options = $.extend( {}, options ); } - const linterOptions = /** @type {import('codemirror/addon/lint/lint').LintStateOptions & (CSSLintRules | JSHintRules | HTMLHintRules) & { rules?: any }} */ ( options ); + const linterOptions = /** @type {CombinedLintOptions} */ ( options ); // Configure JSHint. if ( 'javascript' === settings.codemirror?.mode && settings.jshint ) { @@ -222,10 +226,10 @@ if ( 'undefined' === typeof wp.codeEditor ) { if ( 'htmlmixed' === settings.codemirror?.mode && settings.htmlhint ) { linterOptions.rules = $.extend( {}, settings.htmlhint ); - if ( settings.jshint ) { + if ( settings.jshint && linterOptions.rules ) { linterOptions.rules.jshint = settings.jshint; } - if ( settings.csslint ) { + if ( settings.csslint && linterOptions.rules ) { linterOptions.rules.csslint = settings.csslint; } } @@ -393,7 +397,7 @@ if ( 'undefined' === typeof wp.codeEditor ) { /** * @typedef {object} LintingController - * @property {() => import('codemirror/addon/lint/lint').LintStateOptions|false} getLintOptions - Get lint options. + * @property {() => CombinedLintOptions|false} getLintOptions - Get lint options. * @property {(editor: CodeMirrorEditor) => void} init - Initialize. * @property {(editor: CodeMirrorEditor) => void} updateErrorNotice - Update error notice. */ From bdc959ff701acd88c8b04a89ca5d110ff4d8b6a2 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 22:48:46 -0800 Subject: [PATCH 43/52] Code Editor: Remove remaining 'any' type and streamline event listeners. - Update 'updateErrorNotice' signature to accept the base 'Editor' type, improving compatibility with CodeMirror event listeners. - Register 'updateErrorNotice' directly as a 'blur' listener, eliminating redundant wrapper functions and the need for a type cast. - Update 'LintingController' typedef to match the revised function signature. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/wp/code-editor.js | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index 768864af19d84..9f303d2468e93 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -182,12 +182,12 @@ if ( 'undefined' === typeof wp.codeEditor ) { /** * Call the onUpdateErrorNotice if there are new errors to show. * - * @param {CodeMirrorEditor} editor - Editor. + * @param {import('codemirror').Editor} editor - Editor. * @return {void} */ function updateErrorNotice( editor ) { if ( settings.onUpdateErrorNotice && ! _.isEqual( currentErrorAnnotations, previouslyShownErrorAnnotations ) ) { - settings.onUpdateErrorNotice( currentErrorAnnotations, editor ); + settings.onUpdateErrorNotice( currentErrorAnnotations, /** @type {CodeMirrorEditor} */ ( editor ) ); previouslyShownErrorAnnotations = currentErrorAnnotations; } } @@ -310,19 +310,15 @@ if ( 'undefined' === typeof wp.codeEditor ) { } ); // Update error notice when leaving the editor. - editor.on( 'blur', function() { - updateErrorNotice( editor ); - } ); + editor.on( 'blur', updateErrorNotice ); // Work around hint selection with mouse causing focus to leave editor. editor.on( 'startCompletion', function() { - editor.off( 'blur', ( /** @type {any} */ ( updateErrorNotice ) ) ); + editor.off( 'blur', updateErrorNotice ); } ); editor.on( 'endCompletion', function() { const editorRefocusWait = 500; - editor.on( 'blur', function() { - updateErrorNotice( editor ); - } ); + editor.on( 'blur', updateErrorNotice ); // Wait for editor to possibly get re-focused after selection. _.delay( function() { @@ -399,7 +395,7 @@ if ( 'undefined' === typeof wp.codeEditor ) { * @typedef {object} LintingController * @property {() => CombinedLintOptions|false} getLintOptions - Get lint options. * @property {(editor: CodeMirrorEditor) => void} init - Initialize. - * @property {(editor: CodeMirrorEditor) => void} updateErrorNotice - Update error notice. + * @property {(editor: import('codemirror').Editor) => void} updateErrorNotice - Update error notice. */ /** From ffb7bcc183b682d531e2616115d839afe894acf9 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 22:50:47 -0800 Subject: [PATCH 44/52] Break up long conditional line and remove redundant types --- src/js/_enqueues/wp/code-editor.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index 9f303d2468e93..13a6fb3341616 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -337,7 +337,11 @@ if ( 'undefined' === typeof wp.codeEditor ) { * called. */ $( document.body ).on( 'mousedown', function( /** @type {JQuery.MouseDownEvent} */ event ) { - if ( editor.state.focused && ! editor.getWrapperElement().contains( /** @type {Node} */ ( event.target ) ) && ! ( /** @type {HTMLElement} */ ( event.target ) ).classList.contains( 'CodeMirror-hint' ) ) { + if ( + editor.state.focused && + ! editor.getWrapperElement().contains( event.target ) && + ! event.target.classList.contains( 'CodeMirror-hint' ) + ) { updateErrorNotice( editor ); } } ); From 81179e83ece354cf05f26c5813f9cadb5a8ad9e6 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 22:51:42 -0800 Subject: [PATCH 45/52] Eliminate redundancy in setting same-named variable to key in object literal --- src/js/_enqueues/wp/code-editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index 13a6fb3341616..ac347fd0bbbc5 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -350,7 +350,7 @@ if ( 'undefined' === typeof wp.codeEditor ) { * @param {CodeMirrorEditor} editor - Editor instance. * @return {void} */ - updateErrorNotice: updateErrorNotice + updateErrorNotice, }; } From ba15ab74cfb63c5685d2f450c68b22361b0c0952 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 22:57:31 -0800 Subject: [PATCH 46/52] Code Editor: Add trailing commas to multi-line object literals. Ensure consistency with project formatting standards by adding trailing commas to multi-line object literals in 'code-editor.js', 'javascript-lint.js', and 'htmlhint-kses.js'. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/lib/codemirror/htmlhint-kses.js | 2 +- src/js/_enqueues/wp/code-editor.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/_enqueues/lib/codemirror/htmlhint-kses.js b/src/js/_enqueues/lib/codemirror/htmlhint-kses.js index 669e06ad6289f..0f14e21cdb381 100644 --- a/src/js/_enqueues/lib/codemirror/htmlhint-kses.js +++ b/src/js/_enqueues/lib/codemirror/htmlhint-kses.js @@ -30,5 +30,5 @@ HTMLHint.addRule({ } } }); - } + }, }); diff --git a/src/js/_enqueues/wp/code-editor.js b/src/js/_enqueues/wp/code-editor.js index ac347fd0bbbc5..3553612cca4c4 100644 --- a/src/js/_enqueues/wp/code-editor.js +++ b/src/js/_enqueues/wp/code-editor.js @@ -162,7 +162,7 @@ if ( 'undefined' === typeof wp.codeEditor ) { onTabNext: function() {}, onTabPrevious: function() {}, onChangeLintingErrors: function() {}, - onUpdateErrorNotice: function() {} + onUpdateErrorNotice: function() {}, }; /** From 666a2c1fdd386f8b0c3da540eef6df8f1b96e3c4 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 23:00:03 -0800 Subject: [PATCH 47/52] Code Editor: Refine local ESLint configuration. Update '.eslintrc.json' in 'lib/codemirror/' to use 'overrides', ensuring that only 'javascript-lint.js' is parsed as an ES module while maintaining the default 'script' source type for other files in the directory. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/lib/codemirror/.eslintrc.json | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/js/_enqueues/lib/codemirror/.eslintrc.json b/src/js/_enqueues/lib/codemirror/.eslintrc.json index c3934091caa0f..0e9e7ffa55a16 100644 --- a/src/js/_enqueues/lib/codemirror/.eslintrc.json +++ b/src/js/_enqueues/lib/codemirror/.eslintrc.json @@ -1,6 +1,11 @@ { - "parserOptions": { - "sourceType": "module", - "ecmaVersion": 2020 - } + "overrides": [ + { + "files": [ "javascript-lint.js" ], + "parserOptions": { + "sourceType": "module", + "ecmaVersion": 2020 + } + } + ] } From bf2f38204692af5c05a02ad5ddcdeaaa63cc0002 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 23:05:21 -0800 Subject: [PATCH 48/52] Address ESLint complaints with htmlhint-kses.js --- src/js/_enqueues/lib/codemirror/.eslintrc.json | 6 ++++++ src/js/_enqueues/lib/codemirror/htmlhint-kses.js | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/js/_enqueues/lib/codemirror/.eslintrc.json b/src/js/_enqueues/lib/codemirror/.eslintrc.json index 0e9e7ffa55a16..231dcc0fb3e3c 100644 --- a/src/js/_enqueues/lib/codemirror/.eslintrc.json +++ b/src/js/_enqueues/lib/codemirror/.eslintrc.json @@ -6,6 +6,12 @@ "sourceType": "module", "ecmaVersion": 2020 } + }, + { + "files": [ "htmlhint-kses.js" ], + "parserOptions": { + "ecmaVersion": 2020 + } } ] } diff --git a/src/js/_enqueues/lib/codemirror/htmlhint-kses.js b/src/js/_enqueues/lib/codemirror/htmlhint-kses.js index 0f14e21cdb381..c1c92cf9884b8 100644 --- a/src/js/_enqueues/lib/codemirror/htmlhint-kses.js +++ b/src/js/_enqueues/lib/codemirror/htmlhint-kses.js @@ -1,8 +1,9 @@ /* global HTMLHint */ -/* eslint no-magic-numbers: ["error", { "ignore": [0, 1] }] */ +/* eslint no-magic-numbers: ["error", { "ignore": [1] }] */ HTMLHint.addRule({ id: 'kses', description: 'Element or attribute cannot be used.', + /** * Initialize. * From 0147a63f7eac616dc0db67ba2f54477b660613e9 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 23:06:23 -0800 Subject: [PATCH 49/52] Code Editor: Apply Prettier formatting to htmlhint-kses.js. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- .../_enqueues/lib/codemirror/htmlhint-kses.js | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/js/_enqueues/lib/codemirror/htmlhint-kses.js b/src/js/_enqueues/lib/codemirror/htmlhint-kses.js index c1c92cf9884b8..e08c4c0f5b756 100644 --- a/src/js/_enqueues/lib/codemirror/htmlhint-kses.js +++ b/src/js/_enqueues/lib/codemirror/htmlhint-kses.js @@ -1,6 +1,6 @@ /* global HTMLHint */ /* eslint no-magic-numbers: ["error", { "ignore": [1] }] */ -HTMLHint.addRule({ +HTMLHint.addRule( { id: 'kses', description: 'Element or attribute cannot be used.', @@ -13,13 +13,19 @@ HTMLHint.addRule({ * @param {Record>} options - KSES options. * @return {void} */ - init: function( parser, reporter, options ) { + init: function ( parser, reporter, options ) { 'use strict'; parser.addListener( 'tagstart', ( event ) => { const tagName = event.tagName.toLowerCase(); if ( ! options[ tagName ] ) { - reporter.error( `Tag <${event.tagName}> is not allowed.`, event.line, event.col, this, event.raw ); + reporter.error( + `Tag <${ event.tagName }> is not allowed.`, + event.line, + event.col, + this, + event.raw + ); return; } @@ -27,9 +33,15 @@ HTMLHint.addRule({ const column = event.col + event.tagName.length + 1; for ( const attribute of event.attrs ) { if ( ! allowedAttributes[ attribute.name.toLowerCase() ] ) { - reporter.error( `Tag attribute [${attribute.raw}] is not allowed.`, event.line, column + attribute.index, this, attribute.raw ); + reporter.error( + `Tag attribute [${ attribute.raw }] is not allowed.`, + event.line, + column + attribute.index, + this, + attribute.raw + ); } } - }); + } ); }, -}); +} ); From d33a45c9e409e86ea6d5bfb64f1f24dc4b1a04d4 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 23:16:36 -0800 Subject: [PATCH 50/52] Build Tooling: Revert esprima.js build source to node_modules. Ensure the build process uses the latest version of 'esprima.js' from the npm package, consistent with 'trunk', while keeping the relocated source file in 'src/js/_enqueues/vendor/esprima.js' for development enqueues. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- Gruntfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gruntfile.js b/Gruntfile.js index f86a7d994f492..3e8f6de8f96d7 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -334,7 +334,7 @@ module.exports = function(grunt) { files: [ { [ WORKING_DIR + 'wp-includes/js/codemirror/csslint.js' ]: [ './node_modules/csslint/dist/csslint.js' ], - [ WORKING_DIR + 'wp-includes/js/codemirror/esprima.js' ]: [ './src/js/_enqueues/vendor/esprima.js' ], + [ WORKING_DIR + 'wp-includes/js/codemirror/esprima.js' ]: [ './node_modules/esprima/dist/esprima.js' ], [ WORKING_DIR + 'wp-includes/js/codemirror/htmlhint.js' ]: [ './node_modules/htmlhint/dist/htmlhint.min.js' ], [ WORKING_DIR + 'wp-includes/js/codemirror/jsonlint.js' ]: [ './node_modules/jsonlint/web/jsonlint.js' ], }, From b693399be95f574c027bf2603603238e5e536157 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 13 Feb 2026 23:26:39 -0800 Subject: [PATCH 51/52] Build Tooling: Remove redundant esprima.js source file. Delete 'src/js/_enqueues/vendor/esprima.js' as it is redundant; the build process correctly sources the latest version directly from 'node_modules/esprima/dist/esprima.js', consistent with project standards for third-party libraries. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/js/_enqueues/vendor/esprima.js | 6700 ---------------------------- 1 file changed, 6700 deletions(-) delete mode 100644 src/js/_enqueues/vendor/esprima.js diff --git a/src/js/_enqueues/vendor/esprima.js b/src/js/_enqueues/vendor/esprima.js deleted file mode 100644 index 2c2f93cbd34dd..0000000000000 --- a/src/js/_enqueues/vendor/esprima.js +++ /dev/null @@ -1,6700 +0,0 @@ -(function webpackUniversalModuleDefinition(root, factory) { -/* istanbul ignore next */ - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); -/* istanbul ignore next */ - else if(typeof exports === 'object') - exports["esprima"] = factory(); - else - root["esprima"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; - -/******/ // The require function -/******/ function __webpack_require__(moduleId) { - -/******/ // Check if module is in cache -/* istanbul ignore if */ -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; - -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ exports: {}, -/******/ id: moduleId, -/******/ loaded: false -/******/ }; - -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); - -/******/ // Flag the module as loaded -/******/ module.loaded = true; - -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } - - -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; - -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; - -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; - -/******/ // Load entry module and return exports -/******/ return __webpack_require__(0); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ function(module, exports, __webpack_require__) { - - "use strict"; - /* - Copyright JS Foundation and other contributors, https://js.foundation/ - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - Object.defineProperty(exports, "__esModule", { value: true }); - var comment_handler_1 = __webpack_require__(1); - var jsx_parser_1 = __webpack_require__(3); - var parser_1 = __webpack_require__(8); - var tokenizer_1 = __webpack_require__(15); - function parse(code, options, delegate) { - var commentHandler = null; - var proxyDelegate = function (node, metadata) { - if (delegate) { - delegate(node, metadata); - } - if (commentHandler) { - commentHandler.visit(node, metadata); - } - }; - var parserDelegate = (typeof delegate === 'function') ? proxyDelegate : null; - var collectComment = false; - if (options) { - collectComment = (typeof options.comment === 'boolean' && options.comment); - var attachComment = (typeof options.attachComment === 'boolean' && options.attachComment); - if (collectComment || attachComment) { - commentHandler = new comment_handler_1.CommentHandler(); - commentHandler.attach = attachComment; - options.comment = true; - parserDelegate = proxyDelegate; - } - } - var isModule = false; - if (options && typeof options.sourceType === 'string') { - isModule = (options.sourceType === 'module'); - } - var parser; - if (options && typeof options.jsx === 'boolean' && options.jsx) { - parser = new jsx_parser_1.JSXParser(code, options, parserDelegate); - } - else { - parser = new parser_1.Parser(code, options, parserDelegate); - } - var program = isModule ? parser.parseModule() : parser.parseScript(); - var ast = program; - if (collectComment && commentHandler) { - ast.comments = commentHandler.comments; - } - if (parser.config.tokens) { - ast.tokens = parser.tokens; - } - if (parser.config.tolerant) { - ast.errors = parser.errorHandler.errors; - } - return ast; - } - exports.parse = parse; - function parseModule(code, options, delegate) { - var parsingOptions = options || {}; - parsingOptions.sourceType = 'module'; - return parse(code, parsingOptions, delegate); - } - exports.parseModule = parseModule; - function parseScript(code, options, delegate) { - var parsingOptions = options || {}; - parsingOptions.sourceType = 'script'; - return parse(code, parsingOptions, delegate); - } - exports.parseScript = parseScript; - function tokenize(code, options, delegate) { - var tokenizer = new tokenizer_1.Tokenizer(code, options); - var tokens; - tokens = []; - try { - while (true) { - var token = tokenizer.getNextToken(); - if (!token) { - break; - } - if (delegate) { - token = delegate(token); - } - tokens.push(token); - } - } - catch (e) { - tokenizer.errorHandler.tolerate(e); - } - if (tokenizer.errorHandler.tolerant) { - tokens.errors = tokenizer.errors(); - } - return tokens; - } - exports.tokenize = tokenize; - var syntax_1 = __webpack_require__(2); - exports.Syntax = syntax_1.Syntax; - // Sync with *.json manifests. - exports.version = '4.0.0'; - - -/***/ }, -/* 1 */ -/***/ function(module, exports, __webpack_require__) { - - "use strict"; - Object.defineProperty(exports, "__esModule", { value: true }); - var syntax_1 = __webpack_require__(2); - var CommentHandler = (function () { - function CommentHandler() { - this.attach = false; - this.comments = []; - this.stack = []; - this.leading = []; - this.trailing = []; - } - CommentHandler.prototype.insertInnerComments = function (node, metadata) { - // innnerComments for properties empty block - // `function a() {/** comments **\/}` - if (node.type === syntax_1.Syntax.BlockStatement && node.body.length === 0) { - var innerComments = []; - for (var i = this.leading.length - 1; i >= 0; --i) { - var entry = this.leading[i]; - if (metadata.end.offset >= entry.start) { - innerComments.unshift(entry.comment); - this.leading.splice(i, 1); - this.trailing.splice(i, 1); - } - } - if (innerComments.length) { - node.innerComments = innerComments; - } - } - }; - CommentHandler.prototype.findTrailingComments = function (metadata) { - var trailingComments = []; - if (this.trailing.length > 0) { - for (var i = this.trailing.length - 1; i >= 0; --i) { - var entry_1 = this.trailing[i]; - if (entry_1.start >= metadata.end.offset) { - trailingComments.unshift(entry_1.comment); - } - } - this.trailing.length = 0; - return trailingComments; - } - var entry = this.stack[this.stack.length - 1]; - if (entry && entry.node.trailingComments) { - var firstComment = entry.node.trailingComments[0]; - if (firstComment && firstComment.range[0] >= metadata.end.offset) { - trailingComments = entry.node.trailingComments; - delete entry.node.trailingComments; - } - } - return trailingComments; - }; - CommentHandler.prototype.findLeadingComments = function (metadata) { - var leadingComments = []; - var target; - while (this.stack.length > 0) { - var entry = this.stack[this.stack.length - 1]; - if (entry && entry.start >= metadata.start.offset) { - target = entry.node; - this.stack.pop(); - } - else { - break; - } - } - if (target) { - var count = target.leadingComments ? target.leadingComments.length : 0; - for (var i = count - 1; i >= 0; --i) { - var comment = target.leadingComments[i]; - if (comment.range[1] <= metadata.start.offset) { - leadingComments.unshift(comment); - target.leadingComments.splice(i, 1); - } - } - if (target.leadingComments && target.leadingComments.length === 0) { - delete target.leadingComments; - } - return leadingComments; - } - for (var i = this.leading.length - 1; i >= 0; --i) { - var entry = this.leading[i]; - if (entry.start <= metadata.start.offset) { - leadingComments.unshift(entry.comment); - this.leading.splice(i, 1); - } - } - return leadingComments; - }; - CommentHandler.prototype.visitNode = function (node, metadata) { - if (node.type === syntax_1.Syntax.Program && node.body.length > 0) { - return; - } - this.insertInnerComments(node, metadata); - var trailingComments = this.findTrailingComments(metadata); - var leadingComments = this.findLeadingComments(metadata); - if (leadingComments.length > 0) { - node.leadingComments = leadingComments; - } - if (trailingComments.length > 0) { - node.trailingComments = trailingComments; - } - this.stack.push({ - node: node, - start: metadata.start.offset - }); - }; - CommentHandler.prototype.visitComment = function (node, metadata) { - var type = (node.type[0] === 'L') ? 'Line' : 'Block'; - var comment = { - type: type, - value: node.value - }; - if (node.range) { - comment.range = node.range; - } - if (node.loc) { - comment.loc = node.loc; - } - this.comments.push(comment); - if (this.attach) { - var entry = { - comment: { - type: type, - value: node.value, - range: [metadata.start.offset, metadata.end.offset] - }, - start: metadata.start.offset - }; - if (node.loc) { - entry.comment.loc = node.loc; - } - node.type = type; - this.leading.push(entry); - this.trailing.push(entry); - } - }; - CommentHandler.prototype.visit = function (node, metadata) { - if (node.type === 'LineComment') { - this.visitComment(node, metadata); - } - else if (node.type === 'BlockComment') { - this.visitComment(node, metadata); - } - else if (this.attach) { - this.visitNode(node, metadata); - } - }; - return CommentHandler; - }()); - exports.CommentHandler = CommentHandler; - - -/***/ }, -/* 2 */ -/***/ function(module, exports) { - - "use strict"; - Object.defineProperty(exports, "__esModule", { value: true }); - exports.Syntax = { - AssignmentExpression: 'AssignmentExpression', - AssignmentPattern: 'AssignmentPattern', - ArrayExpression: 'ArrayExpression', - ArrayPattern: 'ArrayPattern', - ArrowFunctionExpression: 'ArrowFunctionExpression', - AwaitExpression: 'AwaitExpression', - BlockStatement: 'BlockStatement', - BinaryExpression: 'BinaryExpression', - BreakStatement: 'BreakStatement', - CallExpression: 'CallExpression', - CatchClause: 'CatchClause', - ClassBody: 'ClassBody', - ClassDeclaration: 'ClassDeclaration', - ClassExpression: 'ClassExpression', - ConditionalExpression: 'ConditionalExpression', - ContinueStatement: 'ContinueStatement', - DoWhileStatement: 'DoWhileStatement', - DebuggerStatement: 'DebuggerStatement', - EmptyStatement: 'EmptyStatement', - ExportAllDeclaration: 'ExportAllDeclaration', - ExportDefaultDeclaration: 'ExportDefaultDeclaration', - ExportNamedDeclaration: 'ExportNamedDeclaration', - ExportSpecifier: 'ExportSpecifier', - ExpressionStatement: 'ExpressionStatement', - ForStatement: 'ForStatement', - ForOfStatement: 'ForOfStatement', - ForInStatement: 'ForInStatement', - FunctionDeclaration: 'FunctionDeclaration', - FunctionExpression: 'FunctionExpression', - Identifier: 'Identifier', - IfStatement: 'IfStatement', - ImportDeclaration: 'ImportDeclaration', - ImportDefaultSpecifier: 'ImportDefaultSpecifier', - ImportNamespaceSpecifier: 'ImportNamespaceSpecifier', - ImportSpecifier: 'ImportSpecifier', - Literal: 'Literal', - LabeledStatement: 'LabeledStatement', - LogicalExpression: 'LogicalExpression', - MemberExpression: 'MemberExpression', - MetaProperty: 'MetaProperty', - MethodDefinition: 'MethodDefinition', - NewExpression: 'NewExpression', - ObjectExpression: 'ObjectExpression', - ObjectPattern: 'ObjectPattern', - Program: 'Program', - Property: 'Property', - RestElement: 'RestElement', - ReturnStatement: 'ReturnStatement', - SequenceExpression: 'SequenceExpression', - SpreadElement: 'SpreadElement', - Super: 'Super', - SwitchCase: 'SwitchCase', - SwitchStatement: 'SwitchStatement', - TaggedTemplateExpression: 'TaggedTemplateExpression', - TemplateElement: 'TemplateElement', - TemplateLiteral: 'TemplateLiteral', - ThisExpression: 'ThisExpression', - ThrowStatement: 'ThrowStatement', - TryStatement: 'TryStatement', - UnaryExpression: 'UnaryExpression', - UpdateExpression: 'UpdateExpression', - VariableDeclaration: 'VariableDeclaration', - VariableDeclarator: 'VariableDeclarator', - WhileStatement: 'WhileStatement', - WithStatement: 'WithStatement', - YieldExpression: 'YieldExpression' - }; - - -/***/ }, -/* 3 */ -/***/ function(module, exports, __webpack_require__) { - - "use strict"; -/* istanbul ignore next */ - var __extends = (this && this.__extends) || (function () { - var extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return function (d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; - })(); - Object.defineProperty(exports, "__esModule", { value: true }); - var character_1 = __webpack_require__(4); - var JSXNode = __webpack_require__(5); - var jsx_syntax_1 = __webpack_require__(6); - var Node = __webpack_require__(7); - var parser_1 = __webpack_require__(8); - var token_1 = __webpack_require__(13); - var xhtml_entities_1 = __webpack_require__(14); - token_1.TokenName[100 /* Identifier */] = 'JSXIdentifier'; - token_1.TokenName[101 /* Text */] = 'JSXText'; - // Fully qualified element name, e.g. returns "svg:path" - function getQualifiedElementName(elementName) { - var qualifiedName; - switch (elementName.type) { - case jsx_syntax_1.JSXSyntax.JSXIdentifier: - var id = elementName; - qualifiedName = id.name; - break; - case jsx_syntax_1.JSXSyntax.JSXNamespacedName: - var ns = elementName; - qualifiedName = getQualifiedElementName(ns.namespace) + ':' + - getQualifiedElementName(ns.name); - break; - case jsx_syntax_1.JSXSyntax.JSXMemberExpression: - var expr = elementName; - qualifiedName = getQualifiedElementName(expr.object) + '.' + - getQualifiedElementName(expr.property); - break; - /* istanbul ignore next */ - default: - break; - } - return qualifiedName; - } - var JSXParser = (function (_super) { - __extends(JSXParser, _super); - function JSXParser(code, options, delegate) { - return _super.call(this, code, options, delegate) || this; - } - JSXParser.prototype.parsePrimaryExpression = function () { - return this.match('<') ? this.parseJSXRoot() : _super.prototype.parsePrimaryExpression.call(this); - }; - JSXParser.prototype.startJSX = function () { - // Unwind the scanner before the lookahead token. - this.scanner.index = this.startMarker.index; - this.scanner.lineNumber = this.startMarker.line; - this.scanner.lineStart = this.startMarker.index - this.startMarker.column; - }; - JSXParser.prototype.finishJSX = function () { - // Prime the next lookahead. - this.nextToken(); - }; - JSXParser.prototype.reenterJSX = function () { - this.startJSX(); - this.expectJSX('}'); - // Pop the closing '}' added from the lookahead. - if (this.config.tokens) { - this.tokens.pop(); - } - }; - JSXParser.prototype.createJSXNode = function () { - this.collectComments(); - return { - index: this.scanner.index, - line: this.scanner.lineNumber, - column: this.scanner.index - this.scanner.lineStart - }; - }; - JSXParser.prototype.createJSXChildNode = function () { - return { - index: this.scanner.index, - line: this.scanner.lineNumber, - column: this.scanner.index - this.scanner.lineStart - }; - }; - JSXParser.prototype.scanXHTMLEntity = function (quote) { - var result = '&'; - var valid = true; - var terminated = false; - var numeric = false; - var hex = false; - while (!this.scanner.eof() && valid && !terminated) { - var ch = this.scanner.source[this.scanner.index]; - if (ch === quote) { - break; - } - terminated = (ch === ';'); - result += ch; - ++this.scanner.index; - if (!terminated) { - switch (result.length) { - case 2: - // e.g. '{' - numeric = (ch === '#'); - break; - case 3: - if (numeric) { - // e.g. 'A' - hex = (ch === 'x'); - valid = hex || character_1.Character.isDecimalDigit(ch.charCodeAt(0)); - numeric = numeric && !hex; - } - break; - default: - valid = valid && !(numeric && !character_1.Character.isDecimalDigit(ch.charCodeAt(0))); - valid = valid && !(hex && !character_1.Character.isHexDigit(ch.charCodeAt(0))); - break; - } - } - } - if (valid && terminated && result.length > 2) { - // e.g. 'A' becomes just '#x41' - var str = result.substr(1, result.length - 2); - if (numeric && str.length > 1) { - result = String.fromCharCode(parseInt(str.substr(1), 10)); - } - else if (hex && str.length > 2) { - result = String.fromCharCode(parseInt('0' + str.substr(1), 16)); - } - else if (!numeric && !hex && xhtml_entities_1.XHTMLEntities[str]) { - result = xhtml_entities_1.XHTMLEntities[str]; - } - } - return result; - }; - // Scan the next JSX token. This replaces Scanner#lex when in JSX mode. - JSXParser.prototype.lexJSX = function () { - var cp = this.scanner.source.charCodeAt(this.scanner.index); - // < > / : = { } - if (cp === 60 || cp === 62 || cp === 47 || cp === 58 || cp === 61 || cp === 123 || cp === 125) { - var value = this.scanner.source[this.scanner.index++]; - return { - type: 7 /* Punctuator */, - value: value, - lineNumber: this.scanner.lineNumber, - lineStart: this.scanner.lineStart, - start: this.scanner.index - 1, - end: this.scanner.index - }; - } - // " ' - if (cp === 34 || cp === 39) { - var start = this.scanner.index; - var quote = this.scanner.source[this.scanner.index++]; - var str = ''; - while (!this.scanner.eof()) { - var ch = this.scanner.source[this.scanner.index++]; - if (ch === quote) { - break; - } - else if (ch === '&') { - str += this.scanXHTMLEntity(quote); - } - else { - str += ch; - } - } - return { - type: 8 /* StringLiteral */, - value: str, - lineNumber: this.scanner.lineNumber, - lineStart: this.scanner.lineStart, - start: start, - end: this.scanner.index - }; - } - // ... or . - if (cp === 46) { - var n1 = this.scanner.source.charCodeAt(this.scanner.index + 1); - var n2 = this.scanner.source.charCodeAt(this.scanner.index + 2); - var value = (n1 === 46 && n2 === 46) ? '...' : '.'; - var start = this.scanner.index; - this.scanner.index += value.length; - return { - type: 7 /* Punctuator */, - value: value, - lineNumber: this.scanner.lineNumber, - lineStart: this.scanner.lineStart, - start: start, - end: this.scanner.index - }; - } - // ` - if (cp === 96) { - // Only placeholder, since it will be rescanned as a real assignment expression. - return { - type: 10 /* Template */, - value: '', - lineNumber: this.scanner.lineNumber, - lineStart: this.scanner.lineStart, - start: this.scanner.index, - end: this.scanner.index - }; - } - // Identifer can not contain backslash (char code 92). - if (character_1.Character.isIdentifierStart(cp) && (cp !== 92)) { - var start = this.scanner.index; - ++this.scanner.index; - while (!this.scanner.eof()) { - var ch = this.scanner.source.charCodeAt(this.scanner.index); - if (character_1.Character.isIdentifierPart(ch) && (ch !== 92)) { - ++this.scanner.index; - } - else if (ch === 45) { - // Hyphen (char code 45) can be part of an identifier. - ++this.scanner.index; - } - else { - break; - } - } - var id = this.scanner.source.slice(start, this.scanner.index); - return { - type: 100 /* Identifier */, - value: id, - lineNumber: this.scanner.lineNumber, - lineStart: this.scanner.lineStart, - start: start, - end: this.scanner.index - }; - } - return this.scanner.lex(); - }; - JSXParser.prototype.nextJSXToken = function () { - this.collectComments(); - this.startMarker.index = this.scanner.index; - this.startMarker.line = this.scanner.lineNumber; - this.startMarker.column = this.scanner.index - this.scanner.lineStart; - var token = this.lexJSX(); - this.lastMarker.index = this.scanner.index; - this.lastMarker.line = this.scanner.lineNumber; - this.lastMarker.column = this.scanner.index - this.scanner.lineStart; - if (this.config.tokens) { - this.tokens.push(this.convertToken(token)); - } - return token; - }; - JSXParser.prototype.nextJSXText = function () { - this.startMarker.index = this.scanner.index; - this.startMarker.line = this.scanner.lineNumber; - this.startMarker.column = this.scanner.index - this.scanner.lineStart; - var start = this.scanner.index; - var text = ''; - while (!this.scanner.eof()) { - var ch = this.scanner.source[this.scanner.index]; - if (ch === '{' || ch === '<') { - break; - } - ++this.scanner.index; - text += ch; - if (character_1.Character.isLineTerminator(ch.charCodeAt(0))) { - ++this.scanner.lineNumber; - if (ch === '\r' && this.scanner.source[this.scanner.index] === '\n') { - ++this.scanner.index; - } - this.scanner.lineStart = this.scanner.index; - } - } - this.lastMarker.index = this.scanner.index; - this.lastMarker.line = this.scanner.lineNumber; - this.lastMarker.column = this.scanner.index - this.scanner.lineStart; - var token = { - type: 101 /* Text */, - value: text, - lineNumber: this.scanner.lineNumber, - lineStart: this.scanner.lineStart, - start: start, - end: this.scanner.index - }; - if ((text.length > 0) && this.config.tokens) { - this.tokens.push(this.convertToken(token)); - } - return token; - }; - JSXParser.prototype.peekJSXToken = function () { - var state = this.scanner.saveState(); - this.scanner.scanComments(); - var next = this.lexJSX(); - this.scanner.restoreState(state); - return next; - }; - // Expect the next JSX token to match the specified punctuator. - // If not, an exception will be thrown. - JSXParser.prototype.expectJSX = function (value) { - var token = this.nextJSXToken(); - if (token.type !== 7 /* Punctuator */ || token.value !== value) { - this.throwUnexpectedToken(token); - } - }; - // Return true if the next JSX token matches the specified punctuator. - JSXParser.prototype.matchJSX = function (value) { - var next = this.peekJSXToken(); - return next.type === 7 /* Punctuator */ && next.value === value; - }; - JSXParser.prototype.parseJSXIdentifier = function () { - var node = this.createJSXNode(); - var token = this.nextJSXToken(); - if (token.type !== 100 /* Identifier */) { - this.throwUnexpectedToken(token); - } - return this.finalize(node, new JSXNode.JSXIdentifier(token.value)); - }; - JSXParser.prototype.parseJSXElementName = function () { - var node = this.createJSXNode(); - var elementName = this.parseJSXIdentifier(); - if (this.matchJSX(':')) { - var namespace = elementName; - this.expectJSX(':'); - var name_1 = this.parseJSXIdentifier(); - elementName = this.finalize(node, new JSXNode.JSXNamespacedName(namespace, name_1)); - } - else if (this.matchJSX('.')) { - while (this.matchJSX('.')) { - var object = elementName; - this.expectJSX('.'); - var property = this.parseJSXIdentifier(); - elementName = this.finalize(node, new JSXNode.JSXMemberExpression(object, property)); - } - } - return elementName; - }; - JSXParser.prototype.parseJSXAttributeName = function () { - var node = this.createJSXNode(); - var attributeName; - var identifier = this.parseJSXIdentifier(); - if (this.matchJSX(':')) { - var namespace = identifier; - this.expectJSX(':'); - var name_2 = this.parseJSXIdentifier(); - attributeName = this.finalize(node, new JSXNode.JSXNamespacedName(namespace, name_2)); - } - else { - attributeName = identifier; - } - return attributeName; - }; - JSXParser.prototype.parseJSXStringLiteralAttribute = function () { - var node = this.createJSXNode(); - var token = this.nextJSXToken(); - if (token.type !== 8 /* StringLiteral */) { - this.throwUnexpectedToken(token); - } - var raw = this.getTokenRaw(token); - return this.finalize(node, new Node.Literal(token.value, raw)); - }; - JSXParser.prototype.parseJSXExpressionAttribute = function () { - var node = this.createJSXNode(); - this.expectJSX('{'); - this.finishJSX(); - if (this.match('}')) { - this.tolerateError('JSX attributes must only be assigned a non-empty expression'); - } - var expression = this.parseAssignmentExpression(); - this.reenterJSX(); - return this.finalize(node, new JSXNode.JSXExpressionContainer(expression)); - }; - JSXParser.prototype.parseJSXAttributeValue = function () { - return this.matchJSX('{') ? this.parseJSXExpressionAttribute() : - this.matchJSX('<') ? this.parseJSXElement() : this.parseJSXStringLiteralAttribute(); - }; - JSXParser.prototype.parseJSXNameValueAttribute = function () { - var node = this.createJSXNode(); - var name = this.parseJSXAttributeName(); - var value = null; - if (this.matchJSX('=')) { - this.expectJSX('='); - value = this.parseJSXAttributeValue(); - } - return this.finalize(node, new JSXNode.JSXAttribute(name, value)); - }; - JSXParser.prototype.parseJSXSpreadAttribute = function () { - var node = this.createJSXNode(); - this.expectJSX('{'); - this.expectJSX('...'); - this.finishJSX(); - var argument = this.parseAssignmentExpression(); - this.reenterJSX(); - return this.finalize(node, new JSXNode.JSXSpreadAttribute(argument)); - }; - JSXParser.prototype.parseJSXAttributes = function () { - var attributes = []; - while (!this.matchJSX('/') && !this.matchJSX('>')) { - var attribute = this.matchJSX('{') ? this.parseJSXSpreadAttribute() : - this.parseJSXNameValueAttribute(); - attributes.push(attribute); - } - return attributes; - }; - JSXParser.prototype.parseJSXOpeningElement = function () { - var node = this.createJSXNode(); - this.expectJSX('<'); - var name = this.parseJSXElementName(); - var attributes = this.parseJSXAttributes(); - var selfClosing = this.matchJSX('/'); - if (selfClosing) { - this.expectJSX('/'); - } - this.expectJSX('>'); - return this.finalize(node, new JSXNode.JSXOpeningElement(name, selfClosing, attributes)); - }; - JSXParser.prototype.parseJSXBoundaryElement = function () { - var node = this.createJSXNode(); - this.expectJSX('<'); - if (this.matchJSX('/')) { - this.expectJSX('/'); - var name_3 = this.parseJSXElementName(); - this.expectJSX('>'); - return this.finalize(node, new JSXNode.JSXClosingElement(name_3)); - } - var name = this.parseJSXElementName(); - var attributes = this.parseJSXAttributes(); - var selfClosing = this.matchJSX('/'); - if (selfClosing) { - this.expectJSX('/'); - } - this.expectJSX('>'); - return this.finalize(node, new JSXNode.JSXOpeningElement(name, selfClosing, attributes)); - }; - JSXParser.prototype.parseJSXEmptyExpression = function () { - var node = this.createJSXChildNode(); - this.collectComments(); - this.lastMarker.index = this.scanner.index; - this.lastMarker.line = this.scanner.lineNumber; - this.lastMarker.column = this.scanner.index - this.scanner.lineStart; - return this.finalize(node, new JSXNode.JSXEmptyExpression()); - }; - JSXParser.prototype.parseJSXExpressionContainer = function () { - var node = this.createJSXNode(); - this.expectJSX('{'); - var expression; - if (this.matchJSX('}')) { - expression = this.parseJSXEmptyExpression(); - this.expectJSX('}'); - } - else { - this.finishJSX(); - expression = this.parseAssignmentExpression(); - this.reenterJSX(); - } - return this.finalize(node, new JSXNode.JSXExpressionContainer(expression)); - }; - JSXParser.prototype.parseJSXChildren = function () { - var children = []; - while (!this.scanner.eof()) { - var node = this.createJSXChildNode(); - var token = this.nextJSXText(); - if (token.start < token.end) { - var raw = this.getTokenRaw(token); - var child = this.finalize(node, new JSXNode.JSXText(token.value, raw)); - children.push(child); - } - if (this.scanner.source[this.scanner.index] === '{') { - var container = this.parseJSXExpressionContainer(); - children.push(container); - } - else { - break; - } - } - return children; - }; - JSXParser.prototype.parseComplexJSXElement = function (el) { - var stack = []; - while (!this.scanner.eof()) { - el.children = el.children.concat(this.parseJSXChildren()); - var node = this.createJSXChildNode(); - var element = this.parseJSXBoundaryElement(); - if (element.type === jsx_syntax_1.JSXSyntax.JSXOpeningElement) { - var opening = element; - if (opening.selfClosing) { - var child = this.finalize(node, new JSXNode.JSXElement(opening, [], null)); - el.children.push(child); - } - else { - stack.push(el); - el = { node: node, opening: opening, closing: null, children: [] }; - } - } - if (element.type === jsx_syntax_1.JSXSyntax.JSXClosingElement) { - el.closing = element; - var open_1 = getQualifiedElementName(el.opening.name); - var close_1 = getQualifiedElementName(el.closing.name); - if (open_1 !== close_1) { - this.tolerateError('Expected corresponding JSX closing tag for %0', open_1); - } - if (stack.length > 0) { - var child = this.finalize(el.node, new JSXNode.JSXElement(el.opening, el.children, el.closing)); - el = stack[stack.length - 1]; - el.children.push(child); - stack.pop(); - } - else { - break; - } - } - } - return el; - }; - JSXParser.prototype.parseJSXElement = function () { - var node = this.createJSXNode(); - var opening = this.parseJSXOpeningElement(); - var children = []; - var closing = null; - if (!opening.selfClosing) { - var el = this.parseComplexJSXElement({ node: node, opening: opening, closing: closing, children: children }); - children = el.children; - closing = el.closing; - } - return this.finalize(node, new JSXNode.JSXElement(opening, children, closing)); - }; - JSXParser.prototype.parseJSXRoot = function () { - // Pop the opening '<' added from the lookahead. - if (this.config.tokens) { - this.tokens.pop(); - } - this.startJSX(); - var element = this.parseJSXElement(); - this.finishJSX(); - return element; - }; - JSXParser.prototype.isStartOfExpression = function () { - return _super.prototype.isStartOfExpression.call(this) || this.match('<'); - }; - return JSXParser; - }(parser_1.Parser)); - exports.JSXParser = JSXParser; - - -/***/ }, -/* 4 */ -/***/ function(module, exports) { - - "use strict"; - Object.defineProperty(exports, "__esModule", { value: true }); - // See also tools/generate-unicode-regex.js. - var Regex = { - // Unicode v8.0.0 NonAsciiIdentifierStart: - NonAsciiIdentifierStart: /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B4\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309B-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D]/, - // Unicode v8.0.0 NonAsciiIdentifierPart: - NonAsciiIdentifierPart: /[\xAA\xB5\xB7\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B4\u08E3-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0AF9\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58-\u0C5A\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D5F-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1369-\u1371\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA8FD\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2F\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDCA-\uDDCC\uDDD0-\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE37\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF00-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF50\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDDD8-\uDDDD\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9\uDF00-\uDF19\uDF1D-\uDF2B\uDF30-\uDF39]|\uD806[\uDCA0-\uDCE9\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF]/ - }; - exports.Character = { - /* tslint:disable:no-bitwise */ - fromCodePoint: function (cp) { - return (cp < 0x10000) ? String.fromCharCode(cp) : - String.fromCharCode(0xD800 + ((cp - 0x10000) >> 10)) + - String.fromCharCode(0xDC00 + ((cp - 0x10000) & 1023)); - }, - // https://tc39.github.io/ecma262/#sec-white-space - isWhiteSpace: function (cp) { - return (cp === 0x20) || (cp === 0x09) || (cp === 0x0B) || (cp === 0x0C) || (cp === 0xA0) || - (cp >= 0x1680 && [0x1680, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(cp) >= 0); - }, - // https://tc39.github.io/ecma262/#sec-line-terminators - isLineTerminator: function (cp) { - return (cp === 0x0A) || (cp === 0x0D) || (cp === 0x2028) || (cp === 0x2029); - }, - // https://tc39.github.io/ecma262/#sec-names-and-keywords - isIdentifierStart: function (cp) { - return (cp === 0x24) || (cp === 0x5F) || - (cp >= 0x41 && cp <= 0x5A) || - (cp >= 0x61 && cp <= 0x7A) || - (cp === 0x5C) || - ((cp >= 0x80) && Regex.NonAsciiIdentifierStart.test(exports.Character.fromCodePoint(cp))); - }, - isIdentifierPart: function (cp) { - return (cp === 0x24) || (cp === 0x5F) || - (cp >= 0x41 && cp <= 0x5A) || - (cp >= 0x61 && cp <= 0x7A) || - (cp >= 0x30 && cp <= 0x39) || - (cp === 0x5C) || - ((cp >= 0x80) && Regex.NonAsciiIdentifierPart.test(exports.Character.fromCodePoint(cp))); - }, - // https://tc39.github.io/ecma262/#sec-literals-numeric-literals - isDecimalDigit: function (cp) { - return (cp >= 0x30 && cp <= 0x39); // 0..9 - }, - isHexDigit: function (cp) { - return (cp >= 0x30 && cp <= 0x39) || - (cp >= 0x41 && cp <= 0x46) || - (cp >= 0x61 && cp <= 0x66); // a..f - }, - isOctalDigit: function (cp) { - return (cp >= 0x30 && cp <= 0x37); // 0..7 - } - }; - - -/***/ }, -/* 5 */ -/***/ function(module, exports, __webpack_require__) { - - "use strict"; - Object.defineProperty(exports, "__esModule", { value: true }); - var jsx_syntax_1 = __webpack_require__(6); - /* tslint:disable:max-classes-per-file */ - var JSXClosingElement = (function () { - function JSXClosingElement(name) { - this.type = jsx_syntax_1.JSXSyntax.JSXClosingElement; - this.name = name; - } - return JSXClosingElement; - }()); - exports.JSXClosingElement = JSXClosingElement; - var JSXElement = (function () { - function JSXElement(openingElement, children, closingElement) { - this.type = jsx_syntax_1.JSXSyntax.JSXElement; - this.openingElement = openingElement; - this.children = children; - this.closingElement = closingElement; - } - return JSXElement; - }()); - exports.JSXElement = JSXElement; - var JSXEmptyExpression = (function () { - function JSXEmptyExpression() { - this.type = jsx_syntax_1.JSXSyntax.JSXEmptyExpression; - } - return JSXEmptyExpression; - }()); - exports.JSXEmptyExpression = JSXEmptyExpression; - var JSXExpressionContainer = (function () { - function JSXExpressionContainer(expression) { - this.type = jsx_syntax_1.JSXSyntax.JSXExpressionContainer; - this.expression = expression; - } - return JSXExpressionContainer; - }()); - exports.JSXExpressionContainer = JSXExpressionContainer; - var JSXIdentifier = (function () { - function JSXIdentifier(name) { - this.type = jsx_syntax_1.JSXSyntax.JSXIdentifier; - this.name = name; - } - return JSXIdentifier; - }()); - exports.JSXIdentifier = JSXIdentifier; - var JSXMemberExpression = (function () { - function JSXMemberExpression(object, property) { - this.type = jsx_syntax_1.JSXSyntax.JSXMemberExpression; - this.object = object; - this.property = property; - } - return JSXMemberExpression; - }()); - exports.JSXMemberExpression = JSXMemberExpression; - var JSXAttribute = (function () { - function JSXAttribute(name, value) { - this.type = jsx_syntax_1.JSXSyntax.JSXAttribute; - this.name = name; - this.value = value; - } - return JSXAttribute; - }()); - exports.JSXAttribute = JSXAttribute; - var JSXNamespacedName = (function () { - function JSXNamespacedName(namespace, name) { - this.type = jsx_syntax_1.JSXSyntax.JSXNamespacedName; - this.namespace = namespace; - this.name = name; - } - return JSXNamespacedName; - }()); - exports.JSXNamespacedName = JSXNamespacedName; - var JSXOpeningElement = (function () { - function JSXOpeningElement(name, selfClosing, attributes) { - this.type = jsx_syntax_1.JSXSyntax.JSXOpeningElement; - this.name = name; - this.selfClosing = selfClosing; - this.attributes = attributes; - } - return JSXOpeningElement; - }()); - exports.JSXOpeningElement = JSXOpeningElement; - var JSXSpreadAttribute = (function () { - function JSXSpreadAttribute(argument) { - this.type = jsx_syntax_1.JSXSyntax.JSXSpreadAttribute; - this.argument = argument; - } - return JSXSpreadAttribute; - }()); - exports.JSXSpreadAttribute = JSXSpreadAttribute; - var JSXText = (function () { - function JSXText(value, raw) { - this.type = jsx_syntax_1.JSXSyntax.JSXText; - this.value = value; - this.raw = raw; - } - return JSXText; - }()); - exports.JSXText = JSXText; - - -/***/ }, -/* 6 */ -/***/ function(module, exports) { - - "use strict"; - Object.defineProperty(exports, "__esModule", { value: true }); - exports.JSXSyntax = { - JSXAttribute: 'JSXAttribute', - JSXClosingElement: 'JSXClosingElement', - JSXElement: 'JSXElement', - JSXEmptyExpression: 'JSXEmptyExpression', - JSXExpressionContainer: 'JSXExpressionContainer', - JSXIdentifier: 'JSXIdentifier', - JSXMemberExpression: 'JSXMemberExpression', - JSXNamespacedName: 'JSXNamespacedName', - JSXOpeningElement: 'JSXOpeningElement', - JSXSpreadAttribute: 'JSXSpreadAttribute', - JSXText: 'JSXText' - }; - - -/***/ }, -/* 7 */ -/***/ function(module, exports, __webpack_require__) { - - "use strict"; - Object.defineProperty(exports, "__esModule", { value: true }); - var syntax_1 = __webpack_require__(2); - /* tslint:disable:max-classes-per-file */ - var ArrayExpression = (function () { - function ArrayExpression(elements) { - this.type = syntax_1.Syntax.ArrayExpression; - this.elements = elements; - } - return ArrayExpression; - }()); - exports.ArrayExpression = ArrayExpression; - var ArrayPattern = (function () { - function ArrayPattern(elements) { - this.type = syntax_1.Syntax.ArrayPattern; - this.elements = elements; - } - return ArrayPattern; - }()); - exports.ArrayPattern = ArrayPattern; - var ArrowFunctionExpression = (function () { - function ArrowFunctionExpression(params, body, expression) { - this.type = syntax_1.Syntax.ArrowFunctionExpression; - this.id = null; - this.params = params; - this.body = body; - this.generator = false; - this.expression = expression; - this.async = false; - } - return ArrowFunctionExpression; - }()); - exports.ArrowFunctionExpression = ArrowFunctionExpression; - var AssignmentExpression = (function () { - function AssignmentExpression(operator, left, right) { - this.type = syntax_1.Syntax.AssignmentExpression; - this.operator = operator; - this.left = left; - this.right = right; - } - return AssignmentExpression; - }()); - exports.AssignmentExpression = AssignmentExpression; - var AssignmentPattern = (function () { - function AssignmentPattern(left, right) { - this.type = syntax_1.Syntax.AssignmentPattern; - this.left = left; - this.right = right; - } - return AssignmentPattern; - }()); - exports.AssignmentPattern = AssignmentPattern; - var AsyncArrowFunctionExpression = (function () { - function AsyncArrowFunctionExpression(params, body, expression) { - this.type = syntax_1.Syntax.ArrowFunctionExpression; - this.id = null; - this.params = params; - this.body = body; - this.generator = false; - this.expression = expression; - this.async = true; - } - return AsyncArrowFunctionExpression; - }()); - exports.AsyncArrowFunctionExpression = AsyncArrowFunctionExpression; - var AsyncFunctionDeclaration = (function () { - function AsyncFunctionDeclaration(id, params, body) { - this.type = syntax_1.Syntax.FunctionDeclaration; - this.id = id; - this.params = params; - this.body = body; - this.generator = false; - this.expression = false; - this.async = true; - } - return AsyncFunctionDeclaration; - }()); - exports.AsyncFunctionDeclaration = AsyncFunctionDeclaration; - var AsyncFunctionExpression = (function () { - function AsyncFunctionExpression(id, params, body) { - this.type = syntax_1.Syntax.FunctionExpression; - this.id = id; - this.params = params; - this.body = body; - this.generator = false; - this.expression = false; - this.async = true; - } - return AsyncFunctionExpression; - }()); - exports.AsyncFunctionExpression = AsyncFunctionExpression; - var AwaitExpression = (function () { - function AwaitExpression(argument) { - this.type = syntax_1.Syntax.AwaitExpression; - this.argument = argument; - } - return AwaitExpression; - }()); - exports.AwaitExpression = AwaitExpression; - var BinaryExpression = (function () { - function BinaryExpression(operator, left, right) { - var logical = (operator === '||' || operator === '&&'); - this.type = logical ? syntax_1.Syntax.LogicalExpression : syntax_1.Syntax.BinaryExpression; - this.operator = operator; - this.left = left; - this.right = right; - } - return BinaryExpression; - }()); - exports.BinaryExpression = BinaryExpression; - var BlockStatement = (function () { - function BlockStatement(body) { - this.type = syntax_1.Syntax.BlockStatement; - this.body = body; - } - return BlockStatement; - }()); - exports.BlockStatement = BlockStatement; - var BreakStatement = (function () { - function BreakStatement(label) { - this.type = syntax_1.Syntax.BreakStatement; - this.label = label; - } - return BreakStatement; - }()); - exports.BreakStatement = BreakStatement; - var CallExpression = (function () { - function CallExpression(callee, args) { - this.type = syntax_1.Syntax.CallExpression; - this.callee = callee; - this.arguments = args; - } - return CallExpression; - }()); - exports.CallExpression = CallExpression; - var CatchClause = (function () { - function CatchClause(param, body) { - this.type = syntax_1.Syntax.CatchClause; - this.param = param; - this.body = body; - } - return CatchClause; - }()); - exports.CatchClause = CatchClause; - var ClassBody = (function () { - function ClassBody(body) { - this.type = syntax_1.Syntax.ClassBody; - this.body = body; - } - return ClassBody; - }()); - exports.ClassBody = ClassBody; - var ClassDeclaration = (function () { - function ClassDeclaration(id, superClass, body) { - this.type = syntax_1.Syntax.ClassDeclaration; - this.id = id; - this.superClass = superClass; - this.body = body; - } - return ClassDeclaration; - }()); - exports.ClassDeclaration = ClassDeclaration; - var ClassExpression = (function () { - function ClassExpression(id, superClass, body) { - this.type = syntax_1.Syntax.ClassExpression; - this.id = id; - this.superClass = superClass; - this.body = body; - } - return ClassExpression; - }()); - exports.ClassExpression = ClassExpression; - var ComputedMemberExpression = (function () { - function ComputedMemberExpression(object, property) { - this.type = syntax_1.Syntax.MemberExpression; - this.computed = true; - this.object = object; - this.property = property; - } - return ComputedMemberExpression; - }()); - exports.ComputedMemberExpression = ComputedMemberExpression; - var ConditionalExpression = (function () { - function ConditionalExpression(test, consequent, alternate) { - this.type = syntax_1.Syntax.ConditionalExpression; - this.test = test; - this.consequent = consequent; - this.alternate = alternate; - } - return ConditionalExpression; - }()); - exports.ConditionalExpression = ConditionalExpression; - var ContinueStatement = (function () { - function ContinueStatement(label) { - this.type = syntax_1.Syntax.ContinueStatement; - this.label = label; - } - return ContinueStatement; - }()); - exports.ContinueStatement = ContinueStatement; - var DebuggerStatement = (function () { - function DebuggerStatement() { - this.type = syntax_1.Syntax.DebuggerStatement; - } - return DebuggerStatement; - }()); - exports.DebuggerStatement = DebuggerStatement; - var Directive = (function () { - function Directive(expression, directive) { - this.type = syntax_1.Syntax.ExpressionStatement; - this.expression = expression; - this.directive = directive; - } - return Directive; - }()); - exports.Directive = Directive; - var DoWhileStatement = (function () { - function DoWhileStatement(body, test) { - this.type = syntax_1.Syntax.DoWhileStatement; - this.body = body; - this.test = test; - } - return DoWhileStatement; - }()); - exports.DoWhileStatement = DoWhileStatement; - var EmptyStatement = (function () { - function EmptyStatement() { - this.type = syntax_1.Syntax.EmptyStatement; - } - return EmptyStatement; - }()); - exports.EmptyStatement = EmptyStatement; - var ExportAllDeclaration = (function () { - function ExportAllDeclaration(source) { - this.type = syntax_1.Syntax.ExportAllDeclaration; - this.source = source; - } - return ExportAllDeclaration; - }()); - exports.ExportAllDeclaration = ExportAllDeclaration; - var ExportDefaultDeclaration = (function () { - function ExportDefaultDeclaration(declaration) { - this.type = syntax_1.Syntax.ExportDefaultDeclaration; - this.declaration = declaration; - } - return ExportDefaultDeclaration; - }()); - exports.ExportDefaultDeclaration = ExportDefaultDeclaration; - var ExportNamedDeclaration = (function () { - function ExportNamedDeclaration(declaration, specifiers, source) { - this.type = syntax_1.Syntax.ExportNamedDeclaration; - this.declaration = declaration; - this.specifiers = specifiers; - this.source = source; - } - return ExportNamedDeclaration; - }()); - exports.ExportNamedDeclaration = ExportNamedDeclaration; - var ExportSpecifier = (function () { - function ExportSpecifier(local, exported) { - this.type = syntax_1.Syntax.ExportSpecifier; - this.exported = exported; - this.local = local; - } - return ExportSpecifier; - }()); - exports.ExportSpecifier = ExportSpecifier; - var ExpressionStatement = (function () { - function ExpressionStatement(expression) { - this.type = syntax_1.Syntax.ExpressionStatement; - this.expression = expression; - } - return ExpressionStatement; - }()); - exports.ExpressionStatement = ExpressionStatement; - var ForInStatement = (function () { - function ForInStatement(left, right, body) { - this.type = syntax_1.Syntax.ForInStatement; - this.left = left; - this.right = right; - this.body = body; - this.each = false; - } - return ForInStatement; - }()); - exports.ForInStatement = ForInStatement; - var ForOfStatement = (function () { - function ForOfStatement(left, right, body) { - this.type = syntax_1.Syntax.ForOfStatement; - this.left = left; - this.right = right; - this.body = body; - } - return ForOfStatement; - }()); - exports.ForOfStatement = ForOfStatement; - var ForStatement = (function () { - function ForStatement(init, test, update, body) { - this.type = syntax_1.Syntax.ForStatement; - this.init = init; - this.test = test; - this.update = update; - this.body = body; - } - return ForStatement; - }()); - exports.ForStatement = ForStatement; - var FunctionDeclaration = (function () { - function FunctionDeclaration(id, params, body, generator) { - this.type = syntax_1.Syntax.FunctionDeclaration; - this.id = id; - this.params = params; - this.body = body; - this.generator = generator; - this.expression = false; - this.async = false; - } - return FunctionDeclaration; - }()); - exports.FunctionDeclaration = FunctionDeclaration; - var FunctionExpression = (function () { - function FunctionExpression(id, params, body, generator) { - this.type = syntax_1.Syntax.FunctionExpression; - this.id = id; - this.params = params; - this.body = body; - this.generator = generator; - this.expression = false; - this.async = false; - } - return FunctionExpression; - }()); - exports.FunctionExpression = FunctionExpression; - var Identifier = (function () { - function Identifier(name) { - this.type = syntax_1.Syntax.Identifier; - this.name = name; - } - return Identifier; - }()); - exports.Identifier = Identifier; - var IfStatement = (function () { - function IfStatement(test, consequent, alternate) { - this.type = syntax_1.Syntax.IfStatement; - this.test = test; - this.consequent = consequent; - this.alternate = alternate; - } - return IfStatement; - }()); - exports.IfStatement = IfStatement; - var ImportDeclaration = (function () { - function ImportDeclaration(specifiers, source) { - this.type = syntax_1.Syntax.ImportDeclaration; - this.specifiers = specifiers; - this.source = source; - } - return ImportDeclaration; - }()); - exports.ImportDeclaration = ImportDeclaration; - var ImportDefaultSpecifier = (function () { - function ImportDefaultSpecifier(local) { - this.type = syntax_1.Syntax.ImportDefaultSpecifier; - this.local = local; - } - return ImportDefaultSpecifier; - }()); - exports.ImportDefaultSpecifier = ImportDefaultSpecifier; - var ImportNamespaceSpecifier = (function () { - function ImportNamespaceSpecifier(local) { - this.type = syntax_1.Syntax.ImportNamespaceSpecifier; - this.local = local; - } - return ImportNamespaceSpecifier; - }()); - exports.ImportNamespaceSpecifier = ImportNamespaceSpecifier; - var ImportSpecifier = (function () { - function ImportSpecifier(local, imported) { - this.type = syntax_1.Syntax.ImportSpecifier; - this.local = local; - this.imported = imported; - } - return ImportSpecifier; - }()); - exports.ImportSpecifier = ImportSpecifier; - var LabeledStatement = (function () { - function LabeledStatement(label, body) { - this.type = syntax_1.Syntax.LabeledStatement; - this.label = label; - this.body = body; - } - return LabeledStatement; - }()); - exports.LabeledStatement = LabeledStatement; - var Literal = (function () { - function Literal(value, raw) { - this.type = syntax_1.Syntax.Literal; - this.value = value; - this.raw = raw; - } - return Literal; - }()); - exports.Literal = Literal; - var MetaProperty = (function () { - function MetaProperty(meta, property) { - this.type = syntax_1.Syntax.MetaProperty; - this.meta = meta; - this.property = property; - } - return MetaProperty; - }()); - exports.MetaProperty = MetaProperty; - var MethodDefinition = (function () { - function MethodDefinition(key, computed, value, kind, isStatic) { - this.type = syntax_1.Syntax.MethodDefinition; - this.key = key; - this.computed = computed; - this.value = value; - this.kind = kind; - this.static = isStatic; - } - return MethodDefinition; - }()); - exports.MethodDefinition = MethodDefinition; - var Module = (function () { - function Module(body) { - this.type = syntax_1.Syntax.Program; - this.body = body; - this.sourceType = 'module'; - } - return Module; - }()); - exports.Module = Module; - var NewExpression = (function () { - function NewExpression(callee, args) { - this.type = syntax_1.Syntax.NewExpression; - this.callee = callee; - this.arguments = args; - } - return NewExpression; - }()); - exports.NewExpression = NewExpression; - var ObjectExpression = (function () { - function ObjectExpression(properties) { - this.type = syntax_1.Syntax.ObjectExpression; - this.properties = properties; - } - return ObjectExpression; - }()); - exports.ObjectExpression = ObjectExpression; - var ObjectPattern = (function () { - function ObjectPattern(properties) { - this.type = syntax_1.Syntax.ObjectPattern; - this.properties = properties; - } - return ObjectPattern; - }()); - exports.ObjectPattern = ObjectPattern; - var Property = (function () { - function Property(kind, key, computed, value, method, shorthand) { - this.type = syntax_1.Syntax.Property; - this.key = key; - this.computed = computed; - this.value = value; - this.kind = kind; - this.method = method; - this.shorthand = shorthand; - } - return Property; - }()); - exports.Property = Property; - var RegexLiteral = (function () { - function RegexLiteral(value, raw, pattern, flags) { - this.type = syntax_1.Syntax.Literal; - this.value = value; - this.raw = raw; - this.regex = { pattern: pattern, flags: flags }; - } - return RegexLiteral; - }()); - exports.RegexLiteral = RegexLiteral; - var RestElement = (function () { - function RestElement(argument) { - this.type = syntax_1.Syntax.RestElement; - this.argument = argument; - } - return RestElement; - }()); - exports.RestElement = RestElement; - var ReturnStatement = (function () { - function ReturnStatement(argument) { - this.type = syntax_1.Syntax.ReturnStatement; - this.argument = argument; - } - return ReturnStatement; - }()); - exports.ReturnStatement = ReturnStatement; - var Script = (function () { - function Script(body) { - this.type = syntax_1.Syntax.Program; - this.body = body; - this.sourceType = 'script'; - } - return Script; - }()); - exports.Script = Script; - var SequenceExpression = (function () { - function SequenceExpression(expressions) { - this.type = syntax_1.Syntax.SequenceExpression; - this.expressions = expressions; - } - return SequenceExpression; - }()); - exports.SequenceExpression = SequenceExpression; - var SpreadElement = (function () { - function SpreadElement(argument) { - this.type = syntax_1.Syntax.SpreadElement; - this.argument = argument; - } - return SpreadElement; - }()); - exports.SpreadElement = SpreadElement; - var StaticMemberExpression = (function () { - function StaticMemberExpression(object, property) { - this.type = syntax_1.Syntax.MemberExpression; - this.computed = false; - this.object = object; - this.property = property; - } - return StaticMemberExpression; - }()); - exports.StaticMemberExpression = StaticMemberExpression; - var Super = (function () { - function Super() { - this.type = syntax_1.Syntax.Super; - } - return Super; - }()); - exports.Super = Super; - var SwitchCase = (function () { - function SwitchCase(test, consequent) { - this.type = syntax_1.Syntax.SwitchCase; - this.test = test; - this.consequent = consequent; - } - return SwitchCase; - }()); - exports.SwitchCase = SwitchCase; - var SwitchStatement = (function () { - function SwitchStatement(discriminant, cases) { - this.type = syntax_1.Syntax.SwitchStatement; - this.discriminant = discriminant; - this.cases = cases; - } - return SwitchStatement; - }()); - exports.SwitchStatement = SwitchStatement; - var TaggedTemplateExpression = (function () { - function TaggedTemplateExpression(tag, quasi) { - this.type = syntax_1.Syntax.TaggedTemplateExpression; - this.tag = tag; - this.quasi = quasi; - } - return TaggedTemplateExpression; - }()); - exports.TaggedTemplateExpression = TaggedTemplateExpression; - var TemplateElement = (function () { - function TemplateElement(value, tail) { - this.type = syntax_1.Syntax.TemplateElement; - this.value = value; - this.tail = tail; - } - return TemplateElement; - }()); - exports.TemplateElement = TemplateElement; - var TemplateLiteral = (function () { - function TemplateLiteral(quasis, expressions) { - this.type = syntax_1.Syntax.TemplateLiteral; - this.quasis = quasis; - this.expressions = expressions; - } - return TemplateLiteral; - }()); - exports.TemplateLiteral = TemplateLiteral; - var ThisExpression = (function () { - function ThisExpression() { - this.type = syntax_1.Syntax.ThisExpression; - } - return ThisExpression; - }()); - exports.ThisExpression = ThisExpression; - var ThrowStatement = (function () { - function ThrowStatement(argument) { - this.type = syntax_1.Syntax.ThrowStatement; - this.argument = argument; - } - return ThrowStatement; - }()); - exports.ThrowStatement = ThrowStatement; - var TryStatement = (function () { - function TryStatement(block, handler, finalizer) { - this.type = syntax_1.Syntax.TryStatement; - this.block = block; - this.handler = handler; - this.finalizer = finalizer; - } - return TryStatement; - }()); - exports.TryStatement = TryStatement; - var UnaryExpression = (function () { - function UnaryExpression(operator, argument) { - this.type = syntax_1.Syntax.UnaryExpression; - this.operator = operator; - this.argument = argument; - this.prefix = true; - } - return UnaryExpression; - }()); - exports.UnaryExpression = UnaryExpression; - var UpdateExpression = (function () { - function UpdateExpression(operator, argument, prefix) { - this.type = syntax_1.Syntax.UpdateExpression; - this.operator = operator; - this.argument = argument; - this.prefix = prefix; - } - return UpdateExpression; - }()); - exports.UpdateExpression = UpdateExpression; - var VariableDeclaration = (function () { - function VariableDeclaration(declarations, kind) { - this.type = syntax_1.Syntax.VariableDeclaration; - this.declarations = declarations; - this.kind = kind; - } - return VariableDeclaration; - }()); - exports.VariableDeclaration = VariableDeclaration; - var VariableDeclarator = (function () { - function VariableDeclarator(id, init) { - this.type = syntax_1.Syntax.VariableDeclarator; - this.id = id; - this.init = init; - } - return VariableDeclarator; - }()); - exports.VariableDeclarator = VariableDeclarator; - var WhileStatement = (function () { - function WhileStatement(test, body) { - this.type = syntax_1.Syntax.WhileStatement; - this.test = test; - this.body = body; - } - return WhileStatement; - }()); - exports.WhileStatement = WhileStatement; - var WithStatement = (function () { - function WithStatement(object, body) { - this.type = syntax_1.Syntax.WithStatement; - this.object = object; - this.body = body; - } - return WithStatement; - }()); - exports.WithStatement = WithStatement; - var YieldExpression = (function () { - function YieldExpression(argument, delegate) { - this.type = syntax_1.Syntax.YieldExpression; - this.argument = argument; - this.delegate = delegate; - } - return YieldExpression; - }()); - exports.YieldExpression = YieldExpression; - - -/***/ }, -/* 8 */ -/***/ function(module, exports, __webpack_require__) { - - "use strict"; - Object.defineProperty(exports, "__esModule", { value: true }); - var assert_1 = __webpack_require__(9); - var error_handler_1 = __webpack_require__(10); - var messages_1 = __webpack_require__(11); - var Node = __webpack_require__(7); - var scanner_1 = __webpack_require__(12); - var syntax_1 = __webpack_require__(2); - var token_1 = __webpack_require__(13); - var ArrowParameterPlaceHolder = 'ArrowParameterPlaceHolder'; - var Parser = (function () { - function Parser(code, options, delegate) { - if (options === void 0) { options = {}; } - this.config = { - range: (typeof options.range === 'boolean') && options.range, - loc: (typeof options.loc === 'boolean') && options.loc, - source: null, - tokens: (typeof options.tokens === 'boolean') && options.tokens, - comment: (typeof options.comment === 'boolean') && options.comment, - tolerant: (typeof options.tolerant === 'boolean') && options.tolerant - }; - if (this.config.loc && options.source && options.source !== null) { - this.config.source = String(options.source); - } - this.delegate = delegate; - this.errorHandler = new error_handler_1.ErrorHandler(); - this.errorHandler.tolerant = this.config.tolerant; - this.scanner = new scanner_1.Scanner(code, this.errorHandler); - this.scanner.trackComment = this.config.comment; - this.operatorPrecedence = { - ')': 0, - ';': 0, - ',': 0, - '=': 0, - ']': 0, - '||': 1, - '&&': 2, - '|': 3, - '^': 4, - '&': 5, - '==': 6, - '!=': 6, - '===': 6, - '!==': 6, - '<': 7, - '>': 7, - '<=': 7, - '>=': 7, - '<<': 8, - '>>': 8, - '>>>': 8, - '+': 9, - '-': 9, - '*': 11, - '/': 11, - '%': 11 - }; - this.lookahead = { - type: 2 /* EOF */, - value: '', - lineNumber: this.scanner.lineNumber, - lineStart: 0, - start: 0, - end: 0 - }; - this.hasLineTerminator = false; - this.context = { - isModule: false, - await: false, - allowIn: true, - allowStrictDirective: true, - allowYield: true, - firstCoverInitializedNameError: null, - isAssignmentTarget: false, - isBindingElement: false, - inFunctionBody: false, - inIteration: false, - inSwitch: false, - labelSet: {}, - strict: false - }; - this.tokens = []; - this.startMarker = { - index: 0, - line: this.scanner.lineNumber, - column: 0 - }; - this.lastMarker = { - index: 0, - line: this.scanner.lineNumber, - column: 0 - }; - this.nextToken(); - this.lastMarker = { - index: this.scanner.index, - line: this.scanner.lineNumber, - column: this.scanner.index - this.scanner.lineStart - }; - } - Parser.prototype.throwError = function (messageFormat) { - var values = []; - for (var _i = 1; _i < arguments.length; _i++) { - values[_i - 1] = arguments[_i]; - } - var args = Array.prototype.slice.call(arguments, 1); - var msg = messageFormat.replace(/%(\d)/g, function (whole, idx) { - assert_1.assert(idx < args.length, 'Message reference must be in range'); - return args[idx]; - }); - var index = this.lastMarker.index; - var line = this.lastMarker.line; - var column = this.lastMarker.column + 1; - throw this.errorHandler.createError(index, line, column, msg); - }; - Parser.prototype.tolerateError = function (messageFormat) { - var values = []; - for (var _i = 1; _i < arguments.length; _i++) { - values[_i - 1] = arguments[_i]; - } - var args = Array.prototype.slice.call(arguments, 1); - var msg = messageFormat.replace(/%(\d)/g, function (whole, idx) { - assert_1.assert(idx < args.length, 'Message reference must be in range'); - return args[idx]; - }); - var index = this.lastMarker.index; - var line = this.scanner.lineNumber; - var column = this.lastMarker.column + 1; - this.errorHandler.tolerateError(index, line, column, msg); - }; - // Throw an exception because of the token. - Parser.prototype.unexpectedTokenError = function (token, message) { - var msg = message || messages_1.Messages.UnexpectedToken; - var value; - if (token) { - if (!message) { - msg = (token.type === 2 /* EOF */) ? messages_1.Messages.UnexpectedEOS : - (token.type === 3 /* Identifier */) ? messages_1.Messages.UnexpectedIdentifier : - (token.type === 6 /* NumericLiteral */) ? messages_1.Messages.UnexpectedNumber : - (token.type === 8 /* StringLiteral */) ? messages_1.Messages.UnexpectedString : - (token.type === 10 /* Template */) ? messages_1.Messages.UnexpectedTemplate : - messages_1.Messages.UnexpectedToken; - if (token.type === 4 /* Keyword */) { - if (this.scanner.isFutureReservedWord(token.value)) { - msg = messages_1.Messages.UnexpectedReserved; - } - else if (this.context.strict && this.scanner.isStrictModeReservedWord(token.value)) { - msg = messages_1.Messages.StrictReservedWord; - } - } - } - value = token.value; - } - else { - value = 'ILLEGAL'; - } - msg = msg.replace('%0', value); - if (token && typeof token.lineNumber === 'number') { - var index = token.start; - var line = token.lineNumber; - var lastMarkerLineStart = this.lastMarker.index - this.lastMarker.column; - var column = token.start - lastMarkerLineStart + 1; - return this.errorHandler.createError(index, line, column, msg); - } - else { - var index = this.lastMarker.index; - var line = this.lastMarker.line; - var column = this.lastMarker.column + 1; - return this.errorHandler.createError(index, line, column, msg); - } - }; - Parser.prototype.throwUnexpectedToken = function (token, message) { - throw this.unexpectedTokenError(token, message); - }; - Parser.prototype.tolerateUnexpectedToken = function (token, message) { - this.errorHandler.tolerate(this.unexpectedTokenError(token, message)); - }; - Parser.prototype.collectComments = function () { - if (!this.config.comment) { - this.scanner.scanComments(); - } - else { - var comments = this.scanner.scanComments(); - if (comments.length > 0 && this.delegate) { - for (var i = 0; i < comments.length; ++i) { - var e = comments[i]; - var node = void 0; - node = { - type: e.multiLine ? 'BlockComment' : 'LineComment', - value: this.scanner.source.slice(e.slice[0], e.slice[1]) - }; - if (this.config.range) { - node.range = e.range; - } - if (this.config.loc) { - node.loc = e.loc; - } - var metadata = { - start: { - line: e.loc.start.line, - column: e.loc.start.column, - offset: e.range[0] - }, - end: { - line: e.loc.end.line, - column: e.loc.end.column, - offset: e.range[1] - } - }; - this.delegate(node, metadata); - } - } - } - }; - // From internal representation to an external structure - Parser.prototype.getTokenRaw = function (token) { - return this.scanner.source.slice(token.start, token.end); - }; - Parser.prototype.convertToken = function (token) { - var t = { - type: token_1.TokenName[token.type], - value: this.getTokenRaw(token) - }; - if (this.config.range) { - t.range = [token.start, token.end]; - } - if (this.config.loc) { - t.loc = { - start: { - line: this.startMarker.line, - column: this.startMarker.column - }, - end: { - line: this.scanner.lineNumber, - column: this.scanner.index - this.scanner.lineStart - } - }; - } - if (token.type === 9 /* RegularExpression */) { - var pattern = token.pattern; - var flags = token.flags; - t.regex = { pattern: pattern, flags: flags }; - } - return t; - }; - Parser.prototype.nextToken = function () { - var token = this.lookahead; - this.lastMarker.index = this.scanner.index; - this.lastMarker.line = this.scanner.lineNumber; - this.lastMarker.column = this.scanner.index - this.scanner.lineStart; - this.collectComments(); - if (this.scanner.index !== this.startMarker.index) { - this.startMarker.index = this.scanner.index; - this.startMarker.line = this.scanner.lineNumber; - this.startMarker.column = this.scanner.index - this.scanner.lineStart; - } - var next = this.scanner.lex(); - this.hasLineTerminator = (token.lineNumber !== next.lineNumber); - if (next && this.context.strict && next.type === 3 /* Identifier */) { - if (this.scanner.isStrictModeReservedWord(next.value)) { - next.type = 4 /* Keyword */; - } - } - this.lookahead = next; - if (this.config.tokens && next.type !== 2 /* EOF */) { - this.tokens.push(this.convertToken(next)); - } - return token; - }; - Parser.prototype.nextRegexToken = function () { - this.collectComments(); - var token = this.scanner.scanRegExp(); - if (this.config.tokens) { - // Pop the previous token, '/' or '/=' - // This is added from the lookahead token. - this.tokens.pop(); - this.tokens.push(this.convertToken(token)); - } - // Prime the next lookahead. - this.lookahead = token; - this.nextToken(); - return token; - }; - Parser.prototype.createNode = function () { - return { - index: this.startMarker.index, - line: this.startMarker.line, - column: this.startMarker.column - }; - }; - Parser.prototype.startNode = function (token) { - return { - index: token.start, - line: token.lineNumber, - column: token.start - token.lineStart - }; - }; - Parser.prototype.finalize = function (marker, node) { - if (this.config.range) { - node.range = [marker.index, this.lastMarker.index]; - } - if (this.config.loc) { - node.loc = { - start: { - line: marker.line, - column: marker.column, - }, - end: { - line: this.lastMarker.line, - column: this.lastMarker.column - } - }; - if (this.config.source) { - node.loc.source = this.config.source; - } - } - if (this.delegate) { - var metadata = { - start: { - line: marker.line, - column: marker.column, - offset: marker.index - }, - end: { - line: this.lastMarker.line, - column: this.lastMarker.column, - offset: this.lastMarker.index - } - }; - this.delegate(node, metadata); - } - return node; - }; - // Expect the next token to match the specified punctuator. - // If not, an exception will be thrown. - Parser.prototype.expect = function (value) { - var token = this.nextToken(); - if (token.type !== 7 /* Punctuator */ || token.value !== value) { - this.throwUnexpectedToken(token); - } - }; - // Quietly expect a comma when in tolerant mode, otherwise delegates to expect(). - Parser.prototype.expectCommaSeparator = function () { - if (this.config.tolerant) { - var token = this.lookahead; - if (token.type === 7 /* Punctuator */ && token.value === ',') { - this.nextToken(); - } - else if (token.type === 7 /* Punctuator */ && token.value === ';') { - this.nextToken(); - this.tolerateUnexpectedToken(token); - } - else { - this.tolerateUnexpectedToken(token, messages_1.Messages.UnexpectedToken); - } - } - else { - this.expect(','); - } - }; - // Expect the next token to match the specified keyword. - // If not, an exception will be thrown. - Parser.prototype.expectKeyword = function (keyword) { - var token = this.nextToken(); - if (token.type !== 4 /* Keyword */ || token.value !== keyword) { - this.throwUnexpectedToken(token); - } - }; - // Return true if the next token matches the specified punctuator. - Parser.prototype.match = function (value) { - return this.lookahead.type === 7 /* Punctuator */ && this.lookahead.value === value; - }; - // Return true if the next token matches the specified keyword - Parser.prototype.matchKeyword = function (keyword) { - return this.lookahead.type === 4 /* Keyword */ && this.lookahead.value === keyword; - }; - // Return true if the next token matches the specified contextual keyword - // (where an identifier is sometimes a keyword depending on the context) - Parser.prototype.matchContextualKeyword = function (keyword) { - return this.lookahead.type === 3 /* Identifier */ && this.lookahead.value === keyword; - }; - // Return true if the next token is an assignment operator - Parser.prototype.matchAssign = function () { - if (this.lookahead.type !== 7 /* Punctuator */) { - return false; - } - var op = this.lookahead.value; - return op === '=' || - op === '*=' || - op === '**=' || - op === '/=' || - op === '%=' || - op === '+=' || - op === '-=' || - op === '<<=' || - op === '>>=' || - op === '>>>=' || - op === '&=' || - op === '^=' || - op === '|='; - }; - // Cover grammar support. - // - // When an assignment expression position starts with an left parenthesis, the determination of the type - // of the syntax is to be deferred arbitrarily long until the end of the parentheses pair (plus a lookahead) - // or the first comma. This situation also defers the determination of all the expressions nested in the pair. - // - // There are three productions that can be parsed in a parentheses pair that needs to be determined - // after the outermost pair is closed. They are: - // - // 1. AssignmentExpression - // 2. BindingElements - // 3. AssignmentTargets - // - // In order to avoid exponential backtracking, we use two flags to denote if the production can be - // binding element or assignment target. - // - // The three productions have the relationship: - // - // BindingElements ⊆ AssignmentTargets ⊆ AssignmentExpression - // - // with a single exception that CoverInitializedName when used directly in an Expression, generates - // an early error. Therefore, we need the third state, firstCoverInitializedNameError, to track the - // first usage of CoverInitializedName and report it when we reached the end of the parentheses pair. - // - // isolateCoverGrammar function runs the given parser function with a new cover grammar context, and it does not - // effect the current flags. This means the production the parser parses is only used as an expression. Therefore - // the CoverInitializedName check is conducted. - // - // inheritCoverGrammar function runs the given parse function with a new cover grammar context, and it propagates - // the flags outside of the parser. This means the production the parser parses is used as a part of a potential - // pattern. The CoverInitializedName check is deferred. - Parser.prototype.isolateCoverGrammar = function (parseFunction) { - var previousIsBindingElement = this.context.isBindingElement; - var previousIsAssignmentTarget = this.context.isAssignmentTarget; - var previousFirstCoverInitializedNameError = this.context.firstCoverInitializedNameError; - this.context.isBindingElement = true; - this.context.isAssignmentTarget = true; - this.context.firstCoverInitializedNameError = null; - var result = parseFunction.call(this); - if (this.context.firstCoverInitializedNameError !== null) { - this.throwUnexpectedToken(this.context.firstCoverInitializedNameError); - } - this.context.isBindingElement = previousIsBindingElement; - this.context.isAssignmentTarget = previousIsAssignmentTarget; - this.context.firstCoverInitializedNameError = previousFirstCoverInitializedNameError; - return result; - }; - Parser.prototype.inheritCoverGrammar = function (parseFunction) { - var previousIsBindingElement = this.context.isBindingElement; - var previousIsAssignmentTarget = this.context.isAssignmentTarget; - var previousFirstCoverInitializedNameError = this.context.firstCoverInitializedNameError; - this.context.isBindingElement = true; - this.context.isAssignmentTarget = true; - this.context.firstCoverInitializedNameError = null; - var result = parseFunction.call(this); - this.context.isBindingElement = this.context.isBindingElement && previousIsBindingElement; - this.context.isAssignmentTarget = this.context.isAssignmentTarget && previousIsAssignmentTarget; - this.context.firstCoverInitializedNameError = previousFirstCoverInitializedNameError || this.context.firstCoverInitializedNameError; - return result; - }; - Parser.prototype.consumeSemicolon = function () { - if (this.match(';')) { - this.nextToken(); - } - else if (!this.hasLineTerminator) { - if (this.lookahead.type !== 2 /* EOF */ && !this.match('}')) { - this.throwUnexpectedToken(this.lookahead); - } - this.lastMarker.index = this.startMarker.index; - this.lastMarker.line = this.startMarker.line; - this.lastMarker.column = this.startMarker.column; - } - }; - // https://tc39.github.io/ecma262/#sec-primary-expression - Parser.prototype.parsePrimaryExpression = function () { - var node = this.createNode(); - var expr; - var token, raw; - switch (this.lookahead.type) { - case 3 /* Identifier */: - if ((this.context.isModule || this.context.await) && this.lookahead.value === 'await') { - this.tolerateUnexpectedToken(this.lookahead); - } - expr = this.matchAsyncFunction() ? this.parseFunctionExpression() : this.finalize(node, new Node.Identifier(this.nextToken().value)); - break; - case 6 /* NumericLiteral */: - case 8 /* StringLiteral */: - if (this.context.strict && this.lookahead.octal) { - this.tolerateUnexpectedToken(this.lookahead, messages_1.Messages.StrictOctalLiteral); - } - this.context.isAssignmentTarget = false; - this.context.isBindingElement = false; - token = this.nextToken(); - raw = this.getTokenRaw(token); - expr = this.finalize(node, new Node.Literal(token.value, raw)); - break; - case 1 /* BooleanLiteral */: - this.context.isAssignmentTarget = false; - this.context.isBindingElement = false; - token = this.nextToken(); - raw = this.getTokenRaw(token); - expr = this.finalize(node, new Node.Literal(token.value === 'true', raw)); - break; - case 5 /* NullLiteral */: - this.context.isAssignmentTarget = false; - this.context.isBindingElement = false; - token = this.nextToken(); - raw = this.getTokenRaw(token); - expr = this.finalize(node, new Node.Literal(null, raw)); - break; - case 10 /* Template */: - expr = this.parseTemplateLiteral(); - break; - case 7 /* Punctuator */: - switch (this.lookahead.value) { - case '(': - this.context.isBindingElement = false; - expr = this.inheritCoverGrammar(this.parseGroupExpression); - break; - case '[': - expr = this.inheritCoverGrammar(this.parseArrayInitializer); - break; - case '{': - expr = this.inheritCoverGrammar(this.parseObjectInitializer); - break; - case '/': - case '/=': - this.context.isAssignmentTarget = false; - this.context.isBindingElement = false; - this.scanner.index = this.startMarker.index; - token = this.nextRegexToken(); - raw = this.getTokenRaw(token); - expr = this.finalize(node, new Node.RegexLiteral(token.regex, raw, token.pattern, token.flags)); - break; - default: - expr = this.throwUnexpectedToken(this.nextToken()); - } - break; - case 4 /* Keyword */: - if (!this.context.strict && this.context.allowYield && this.matchKeyword('yield')) { - expr = this.parseIdentifierName(); - } - else if (!this.context.strict && this.matchKeyword('let')) { - expr = this.finalize(node, new Node.Identifier(this.nextToken().value)); - } - else { - this.context.isAssignmentTarget = false; - this.context.isBindingElement = false; - if (this.matchKeyword('function')) { - expr = this.parseFunctionExpression(); - } - else if (this.matchKeyword('this')) { - this.nextToken(); - expr = this.finalize(node, new Node.ThisExpression()); - } - else if (this.matchKeyword('class')) { - expr = this.parseClassExpression(); - } - else { - expr = this.throwUnexpectedToken(this.nextToken()); - } - } - break; - default: - expr = this.throwUnexpectedToken(this.nextToken()); - } - return expr; - }; - // https://tc39.github.io/ecma262/#sec-array-initializer - Parser.prototype.parseSpreadElement = function () { - var node = this.createNode(); - this.expect('...'); - var arg = this.inheritCoverGrammar(this.parseAssignmentExpression); - return this.finalize(node, new Node.SpreadElement(arg)); - }; - Parser.prototype.parseArrayInitializer = function () { - var node = this.createNode(); - var elements = []; - this.expect('['); - while (!this.match(']')) { - if (this.match(',')) { - this.nextToken(); - elements.push(null); - } - else if (this.match('...')) { - var element = this.parseSpreadElement(); - if (!this.match(']')) { - this.context.isAssignmentTarget = false; - this.context.isBindingElement = false; - this.expect(','); - } - elements.push(element); - } - else { - elements.push(this.inheritCoverGrammar(this.parseAssignmentExpression)); - if (!this.match(']')) { - this.expect(','); - } - } - } - this.expect(']'); - return this.finalize(node, new Node.ArrayExpression(elements)); - }; - // https://tc39.github.io/ecma262/#sec-object-initializer - Parser.prototype.parsePropertyMethod = function (params) { - this.context.isAssignmentTarget = false; - this.context.isBindingElement = false; - var previousStrict = this.context.strict; - var previousAllowStrictDirective = this.context.allowStrictDirective; - this.context.allowStrictDirective = params.simple; - var body = this.isolateCoverGrammar(this.parseFunctionSourceElements); - if (this.context.strict && params.firstRestricted) { - this.tolerateUnexpectedToken(params.firstRestricted, params.message); - } - if (this.context.strict && params.stricted) { - this.tolerateUnexpectedToken(params.stricted, params.message); - } - this.context.strict = previousStrict; - this.context.allowStrictDirective = previousAllowStrictDirective; - return body; - }; - Parser.prototype.parsePropertyMethodFunction = function () { - var isGenerator = false; - var node = this.createNode(); - var previousAllowYield = this.context.allowYield; - this.context.allowYield = false; - var params = this.parseFormalParameters(); - var method = this.parsePropertyMethod(params); - this.context.allowYield = previousAllowYield; - return this.finalize(node, new Node.FunctionExpression(null, params.params, method, isGenerator)); - }; - Parser.prototype.parsePropertyMethodAsyncFunction = function () { - var node = this.createNode(); - var previousAllowYield = this.context.allowYield; - var previousAwait = this.context.await; - this.context.allowYield = false; - this.context.await = true; - var params = this.parseFormalParameters(); - var method = this.parsePropertyMethod(params); - this.context.allowYield = previousAllowYield; - this.context.await = previousAwait; - return this.finalize(node, new Node.AsyncFunctionExpression(null, params.params, method)); - }; - Parser.prototype.parseObjectPropertyKey = function () { - var node = this.createNode(); - var token = this.nextToken(); - var key; - switch (token.type) { - case 8 /* StringLiteral */: - case 6 /* NumericLiteral */: - if (this.context.strict && token.octal) { - this.tolerateUnexpectedToken(token, messages_1.Messages.StrictOctalLiteral); - } - var raw = this.getTokenRaw(token); - key = this.finalize(node, new Node.Literal(token.value, raw)); - break; - case 3 /* Identifier */: - case 1 /* BooleanLiteral */: - case 5 /* NullLiteral */: - case 4 /* Keyword */: - key = this.finalize(node, new Node.Identifier(token.value)); - break; - case 7 /* Punctuator */: - if (token.value === '[') { - key = this.isolateCoverGrammar(this.parseAssignmentExpression); - this.expect(']'); - } - else { - key = this.throwUnexpectedToken(token); - } - break; - default: - key = this.throwUnexpectedToken(token); - } - return key; - }; - Parser.prototype.isPropertyKey = function (key, value) { - return (key.type === syntax_1.Syntax.Identifier && key.name === value) || - (key.type === syntax_1.Syntax.Literal && key.value === value); - }; - Parser.prototype.parseObjectProperty = function (hasProto) { - var node = this.createNode(); - var token = this.lookahead; - var kind; - var key = null; - var value = null; - var computed = false; - var method = false; - var shorthand = false; - var isAsync = false; - if (token.type === 3 /* Identifier */) { - var id = token.value; - this.nextToken(); - computed = this.match('['); - isAsync = !this.hasLineTerminator && (id === 'async') && - !this.match(':') && !this.match('(') && !this.match('*'); - key = isAsync ? this.parseObjectPropertyKey() : this.finalize(node, new Node.Identifier(id)); - } - else if (this.match('*')) { - this.nextToken(); - } - else { - computed = this.match('['); - key = this.parseObjectPropertyKey(); - } - var lookaheadPropertyKey = this.qualifiedPropertyName(this.lookahead); - if (token.type === 3 /* Identifier */ && !isAsync && token.value === 'get' && lookaheadPropertyKey) { - kind = 'get'; - computed = this.match('['); - key = this.parseObjectPropertyKey(); - this.context.allowYield = false; - value = this.parseGetterMethod(); - } - else if (token.type === 3 /* Identifier */ && !isAsync && token.value === 'set' && lookaheadPropertyKey) { - kind = 'set'; - computed = this.match('['); - key = this.parseObjectPropertyKey(); - value = this.parseSetterMethod(); - } - else if (token.type === 7 /* Punctuator */ && token.value === '*' && lookaheadPropertyKey) { - kind = 'init'; - computed = this.match('['); - key = this.parseObjectPropertyKey(); - value = this.parseGeneratorMethod(); - method = true; - } - else { - if (!key) { - this.throwUnexpectedToken(this.lookahead); - } - kind = 'init'; - if (this.match(':') && !isAsync) { - if (!computed && this.isPropertyKey(key, '__proto__')) { - if (hasProto.value) { - this.tolerateError(messages_1.Messages.DuplicateProtoProperty); - } - hasProto.value = true; - } - this.nextToken(); - value = this.inheritCoverGrammar(this.parseAssignmentExpression); - } - else if (this.match('(')) { - value = isAsync ? this.parsePropertyMethodAsyncFunction() : this.parsePropertyMethodFunction(); - method = true; - } - else if (token.type === 3 /* Identifier */) { - var id = this.finalize(node, new Node.Identifier(token.value)); - if (this.match('=')) { - this.context.firstCoverInitializedNameError = this.lookahead; - this.nextToken(); - shorthand = true; - var init = this.isolateCoverGrammar(this.parseAssignmentExpression); - value = this.finalize(node, new Node.AssignmentPattern(id, init)); - } - else { - shorthand = true; - value = id; - } - } - else { - this.throwUnexpectedToken(this.nextToken()); - } - } - return this.finalize(node, new Node.Property(kind, key, computed, value, method, shorthand)); - }; - Parser.prototype.parseObjectInitializer = function () { - var node = this.createNode(); - this.expect('{'); - var properties = []; - var hasProto = { value: false }; - while (!this.match('}')) { - properties.push(this.parseObjectProperty(hasProto)); - if (!this.match('}')) { - this.expectCommaSeparator(); - } - } - this.expect('}'); - return this.finalize(node, new Node.ObjectExpression(properties)); - }; - // https://tc39.github.io/ecma262/#sec-template-literals - Parser.prototype.parseTemplateHead = function () { - assert_1.assert(this.lookahead.head, 'Template literal must start with a template head'); - var node = this.createNode(); - var token = this.nextToken(); - var raw = token.value; - var cooked = token.cooked; - return this.finalize(node, new Node.TemplateElement({ raw: raw, cooked: cooked }, token.tail)); - }; - Parser.prototype.parseTemplateElement = function () { - if (this.lookahead.type !== 10 /* Template */) { - this.throwUnexpectedToken(); - } - var node = this.createNode(); - var token = this.nextToken(); - var raw = token.value; - var cooked = token.cooked; - return this.finalize(node, new Node.TemplateElement({ raw: raw, cooked: cooked }, token.tail)); - }; - Parser.prototype.parseTemplateLiteral = function () { - var node = this.createNode(); - var expressions = []; - var quasis = []; - var quasi = this.parseTemplateHead(); - quasis.push(quasi); - while (!quasi.tail) { - expressions.push(this.parseExpression()); - quasi = this.parseTemplateElement(); - quasis.push(quasi); - } - return this.finalize(node, new Node.TemplateLiteral(quasis, expressions)); - }; - // https://tc39.github.io/ecma262/#sec-grouping-operator - Parser.prototype.reinterpretExpressionAsPattern = function (expr) { - switch (expr.type) { - case syntax_1.Syntax.Identifier: - case syntax_1.Syntax.MemberExpression: - case syntax_1.Syntax.RestElement: - case syntax_1.Syntax.AssignmentPattern: - break; - case syntax_1.Syntax.SpreadElement: - expr.type = syntax_1.Syntax.RestElement; - this.reinterpretExpressionAsPattern(expr.argument); - break; - case syntax_1.Syntax.ArrayExpression: - expr.type = syntax_1.Syntax.ArrayPattern; - for (var i = 0; i < expr.elements.length; i++) { - if (expr.elements[i] !== null) { - this.reinterpretExpressionAsPattern(expr.elements[i]); - } - } - break; - case syntax_1.Syntax.ObjectExpression: - expr.type = syntax_1.Syntax.ObjectPattern; - for (var i = 0; i < expr.properties.length; i++) { - this.reinterpretExpressionAsPattern(expr.properties[i].value); - } - break; - case syntax_1.Syntax.AssignmentExpression: - expr.type = syntax_1.Syntax.AssignmentPattern; - delete expr.operator; - this.reinterpretExpressionAsPattern(expr.left); - break; - default: - // Allow other node type for tolerant parsing. - break; - } - }; - Parser.prototype.parseGroupExpression = function () { - var expr; - this.expect('('); - if (this.match(')')) { - this.nextToken(); - if (!this.match('=>')) { - this.expect('=>'); - } - expr = { - type: ArrowParameterPlaceHolder, - params: [], - async: false - }; - } - else { - var startToken = this.lookahead; - var params = []; - if (this.match('...')) { - expr = this.parseRestElement(params); - this.expect(')'); - if (!this.match('=>')) { - this.expect('=>'); - } - expr = { - type: ArrowParameterPlaceHolder, - params: [expr], - async: false - }; - } - else { - var arrow = false; - this.context.isBindingElement = true; - expr = this.inheritCoverGrammar(this.parseAssignmentExpression); - if (this.match(',')) { - var expressions = []; - this.context.isAssignmentTarget = false; - expressions.push(expr); - while (this.lookahead.type !== 2 /* EOF */) { - if (!this.match(',')) { - break; - } - this.nextToken(); - if (this.match(')')) { - this.nextToken(); - for (var i = 0; i < expressions.length; i++) { - this.reinterpretExpressionAsPattern(expressions[i]); - } - arrow = true; - expr = { - type: ArrowParameterPlaceHolder, - params: expressions, - async: false - }; - } - else if (this.match('...')) { - if (!this.context.isBindingElement) { - this.throwUnexpectedToken(this.lookahead); - } - expressions.push(this.parseRestElement(params)); - this.expect(')'); - if (!this.match('=>')) { - this.expect('=>'); - } - this.context.isBindingElement = false; - for (var i = 0; i < expressions.length; i++) { - this.reinterpretExpressionAsPattern(expressions[i]); - } - arrow = true; - expr = { - type: ArrowParameterPlaceHolder, - params: expressions, - async: false - }; - } - else { - expressions.push(this.inheritCoverGrammar(this.parseAssignmentExpression)); - } - if (arrow) { - break; - } - } - if (!arrow) { - expr = this.finalize(this.startNode(startToken), new Node.SequenceExpression(expressions)); - } - } - if (!arrow) { - this.expect(')'); - if (this.match('=>')) { - if (expr.type === syntax_1.Syntax.Identifier && expr.name === 'yield') { - arrow = true; - expr = { - type: ArrowParameterPlaceHolder, - params: [expr], - async: false - }; - } - if (!arrow) { - if (!this.context.isBindingElement) { - this.throwUnexpectedToken(this.lookahead); - } - if (expr.type === syntax_1.Syntax.SequenceExpression) { - for (var i = 0; i < expr.expressions.length; i++) { - this.reinterpretExpressionAsPattern(expr.expressions[i]); - } - } - else { - this.reinterpretExpressionAsPattern(expr); - } - var parameters = (expr.type === syntax_1.Syntax.SequenceExpression ? expr.expressions : [expr]); - expr = { - type: ArrowParameterPlaceHolder, - params: parameters, - async: false - }; - } - } - this.context.isBindingElement = false; - } - } - } - return expr; - }; - // https://tc39.github.io/ecma262/#sec-left-hand-side-expressions - Parser.prototype.parseArguments = function () { - this.expect('('); - var args = []; - if (!this.match(')')) { - while (true) { - var expr = this.match('...') ? this.parseSpreadElement() : - this.isolateCoverGrammar(this.parseAssignmentExpression); - args.push(expr); - if (this.match(')')) { - break; - } - this.expectCommaSeparator(); - if (this.match(')')) { - break; - } - } - } - this.expect(')'); - return args; - }; - Parser.prototype.isIdentifierName = function (token) { - return token.type === 3 /* Identifier */ || - token.type === 4 /* Keyword */ || - token.type === 1 /* BooleanLiteral */ || - token.type === 5 /* NullLiteral */; - }; - Parser.prototype.parseIdentifierName = function () { - var node = this.createNode(); - var token = this.nextToken(); - if (!this.isIdentifierName(token)) { - this.throwUnexpectedToken(token); - } - return this.finalize(node, new Node.Identifier(token.value)); - }; - Parser.prototype.parseNewExpression = function () { - var node = this.createNode(); - var id = this.parseIdentifierName(); - assert_1.assert(id.name === 'new', 'New expression must start with `new`'); - var expr; - if (this.match('.')) { - this.nextToken(); - if (this.lookahead.type === 3 /* Identifier */ && this.context.inFunctionBody && this.lookahead.value === 'target') { - var property = this.parseIdentifierName(); - expr = new Node.MetaProperty(id, property); - } - else { - this.throwUnexpectedToken(this.lookahead); - } - } - else { - var callee = this.isolateCoverGrammar(this.parseLeftHandSideExpression); - var args = this.match('(') ? this.parseArguments() : []; - expr = new Node.NewExpression(callee, args); - this.context.isAssignmentTarget = false; - this.context.isBindingElement = false; - } - return this.finalize(node, expr); - }; - Parser.prototype.parseAsyncArgument = function () { - var arg = this.parseAssignmentExpression(); - this.context.firstCoverInitializedNameError = null; - return arg; - }; - Parser.prototype.parseAsyncArguments = function () { - this.expect('('); - var args = []; - if (!this.match(')')) { - while (true) { - var expr = this.match('...') ? this.parseSpreadElement() : - this.isolateCoverGrammar(this.parseAsyncArgument); - args.push(expr); - if (this.match(')')) { - break; - } - this.expectCommaSeparator(); - if (this.match(')')) { - break; - } - } - } - this.expect(')'); - return args; - }; - Parser.prototype.parseLeftHandSideExpressionAllowCall = function () { - var startToken = this.lookahead; - var maybeAsync = this.matchContextualKeyword('async'); - var previousAllowIn = this.context.allowIn; - this.context.allowIn = true; - var expr; - if (this.matchKeyword('super') && this.context.inFunctionBody) { - expr = this.createNode(); - this.nextToken(); - expr = this.finalize(expr, new Node.Super()); - if (!this.match('(') && !this.match('.') && !this.match('[')) { - this.throwUnexpectedToken(this.lookahead); - } - } - else { - expr = this.inheritCoverGrammar(this.matchKeyword('new') ? this.parseNewExpression : this.parsePrimaryExpression); - } - while (true) { - if (this.match('.')) { - this.context.isBindingElement = false; - this.context.isAssignmentTarget = true; - this.expect('.'); - var property = this.parseIdentifierName(); - expr = this.finalize(this.startNode(startToken), new Node.StaticMemberExpression(expr, property)); - } - else if (this.match('(')) { - var asyncArrow = maybeAsync && (startToken.lineNumber === this.lookahead.lineNumber); - this.context.isBindingElement = false; - this.context.isAssignmentTarget = false; - var args = asyncArrow ? this.parseAsyncArguments() : this.parseArguments(); - expr = this.finalize(this.startNode(startToken), new Node.CallExpression(expr, args)); - if (asyncArrow && this.match('=>')) { - for (var i = 0; i < args.length; ++i) { - this.reinterpretExpressionAsPattern(args[i]); - } - expr = { - type: ArrowParameterPlaceHolder, - params: args, - async: true - }; - } - } - else if (this.match('[')) { - this.context.isBindingElement = false; - this.context.isAssignmentTarget = true; - this.expect('['); - var property = this.isolateCoverGrammar(this.parseExpression); - this.expect(']'); - expr = this.finalize(this.startNode(startToken), new Node.ComputedMemberExpression(expr, property)); - } - else if (this.lookahead.type === 10 /* Template */ && this.lookahead.head) { - var quasi = this.parseTemplateLiteral(); - expr = this.finalize(this.startNode(startToken), new Node.TaggedTemplateExpression(expr, quasi)); - } - else { - break; - } - } - this.context.allowIn = previousAllowIn; - return expr; - }; - Parser.prototype.parseSuper = function () { - var node = this.createNode(); - this.expectKeyword('super'); - if (!this.match('[') && !this.match('.')) { - this.throwUnexpectedToken(this.lookahead); - } - return this.finalize(node, new Node.Super()); - }; - Parser.prototype.parseLeftHandSideExpression = function () { - assert_1.assert(this.context.allowIn, 'callee of new expression always allow in keyword.'); - var node = this.startNode(this.lookahead); - var expr = (this.matchKeyword('super') && this.context.inFunctionBody) ? this.parseSuper() : - this.inheritCoverGrammar(this.matchKeyword('new') ? this.parseNewExpression : this.parsePrimaryExpression); - while (true) { - if (this.match('[')) { - this.context.isBindingElement = false; - this.context.isAssignmentTarget = true; - this.expect('['); - var property = this.isolateCoverGrammar(this.parseExpression); - this.expect(']'); - expr = this.finalize(node, new Node.ComputedMemberExpression(expr, property)); - } - else if (this.match('.')) { - this.context.isBindingElement = false; - this.context.isAssignmentTarget = true; - this.expect('.'); - var property = this.parseIdentifierName(); - expr = this.finalize(node, new Node.StaticMemberExpression(expr, property)); - } - else if (this.lookahead.type === 10 /* Template */ && this.lookahead.head) { - var quasi = this.parseTemplateLiteral(); - expr = this.finalize(node, new Node.TaggedTemplateExpression(expr, quasi)); - } - else { - break; - } - } - return expr; - }; - // https://tc39.github.io/ecma262/#sec-update-expressions - Parser.prototype.parseUpdateExpression = function () { - var expr; - var startToken = this.lookahead; - if (this.match('++') || this.match('--')) { - var node = this.startNode(startToken); - var token = this.nextToken(); - expr = this.inheritCoverGrammar(this.parseUnaryExpression); - if (this.context.strict && expr.type === syntax_1.Syntax.Identifier && this.scanner.isRestrictedWord(expr.name)) { - this.tolerateError(messages_1.Messages.StrictLHSPrefix); - } - if (!this.context.isAssignmentTarget) { - this.tolerateError(messages_1.Messages.InvalidLHSInAssignment); - } - var prefix = true; - expr = this.finalize(node, new Node.UpdateExpression(token.value, expr, prefix)); - this.context.isAssignmentTarget = false; - this.context.isBindingElement = false; - } - else { - expr = this.inheritCoverGrammar(this.parseLeftHandSideExpressionAllowCall); - if (!this.hasLineTerminator && this.lookahead.type === 7 /* Punctuator */) { - if (this.match('++') || this.match('--')) { - if (this.context.strict && expr.type === syntax_1.Syntax.Identifier && this.scanner.isRestrictedWord(expr.name)) { - this.tolerateError(messages_1.Messages.StrictLHSPostfix); - } - if (!this.context.isAssignmentTarget) { - this.tolerateError(messages_1.Messages.InvalidLHSInAssignment); - } - this.context.isAssignmentTarget = false; - this.context.isBindingElement = false; - var operator = this.nextToken().value; - var prefix = false; - expr = this.finalize(this.startNode(startToken), new Node.UpdateExpression(operator, expr, prefix)); - } - } - } - return expr; - }; - // https://tc39.github.io/ecma262/#sec-unary-operators - Parser.prototype.parseAwaitExpression = function () { - var node = this.createNode(); - this.nextToken(); - var argument = this.parseUnaryExpression(); - return this.finalize(node, new Node.AwaitExpression(argument)); - }; - Parser.prototype.parseUnaryExpression = function () { - var expr; - if (this.match('+') || this.match('-') || this.match('~') || this.match('!') || - this.matchKeyword('delete') || this.matchKeyword('void') || this.matchKeyword('typeof')) { - var node = this.startNode(this.lookahead); - var token = this.nextToken(); - expr = this.inheritCoverGrammar(this.parseUnaryExpression); - expr = this.finalize(node, new Node.UnaryExpression(token.value, expr)); - if (this.context.strict && expr.operator === 'delete' && expr.argument.type === syntax_1.Syntax.Identifier) { - this.tolerateError(messages_1.Messages.StrictDelete); - } - this.context.isAssignmentTarget = false; - this.context.isBindingElement = false; - } - else if (this.context.await && this.matchContextualKeyword('await')) { - expr = this.parseAwaitExpression(); - } - else { - expr = this.parseUpdateExpression(); - } - return expr; - }; - Parser.prototype.parseExponentiationExpression = function () { - var startToken = this.lookahead; - var expr = this.inheritCoverGrammar(this.parseUnaryExpression); - if (expr.type !== syntax_1.Syntax.UnaryExpression && this.match('**')) { - this.nextToken(); - this.context.isAssignmentTarget = false; - this.context.isBindingElement = false; - var left = expr; - var right = this.isolateCoverGrammar(this.parseExponentiationExpression); - expr = this.finalize(this.startNode(startToken), new Node.BinaryExpression('**', left, right)); - } - return expr; - }; - // https://tc39.github.io/ecma262/#sec-exp-operator - // https://tc39.github.io/ecma262/#sec-multiplicative-operators - // https://tc39.github.io/ecma262/#sec-additive-operators - // https://tc39.github.io/ecma262/#sec-bitwise-shift-operators - // https://tc39.github.io/ecma262/#sec-relational-operators - // https://tc39.github.io/ecma262/#sec-equality-operators - // https://tc39.github.io/ecma262/#sec-binary-bitwise-operators - // https://tc39.github.io/ecma262/#sec-binary-logical-operators - Parser.prototype.binaryPrecedence = function (token) { - var op = token.value; - var precedence; - if (token.type === 7 /* Punctuator */) { - precedence = this.operatorPrecedence[op] || 0; - } - else if (token.type === 4 /* Keyword */) { - precedence = (op === 'instanceof' || (this.context.allowIn && op === 'in')) ? 7 : 0; - } - else { - precedence = 0; - } - return precedence; - }; - Parser.prototype.parseBinaryExpression = function () { - var startToken = this.lookahead; - var expr = this.inheritCoverGrammar(this.parseExponentiationExpression); - var token = this.lookahead; - var prec = this.binaryPrecedence(token); - if (prec > 0) { - this.nextToken(); - this.context.isAssignmentTarget = false; - this.context.isBindingElement = false; - var markers = [startToken, this.lookahead]; - var left = expr; - var right = this.isolateCoverGrammar(this.parseExponentiationExpression); - var stack = [left, token.value, right]; - var precedences = [prec]; - while (true) { - prec = this.binaryPrecedence(this.lookahead); - if (prec <= 0) { - break; - } - // Reduce: make a binary expression from the three topmost entries. - while ((stack.length > 2) && (prec <= precedences[precedences.length - 1])) { - right = stack.pop(); - var operator = stack.pop(); - precedences.pop(); - left = stack.pop(); - markers.pop(); - var node = this.startNode(markers[markers.length - 1]); - stack.push(this.finalize(node, new Node.BinaryExpression(operator, left, right))); - } - // Shift. - stack.push(this.nextToken().value); - precedences.push(prec); - markers.push(this.lookahead); - stack.push(this.isolateCoverGrammar(this.parseExponentiationExpression)); - } - // Final reduce to clean-up the stack. - var i = stack.length - 1; - expr = stack[i]; - markers.pop(); - while (i > 1) { - var node = this.startNode(markers.pop()); - var operator = stack[i - 1]; - expr = this.finalize(node, new Node.BinaryExpression(operator, stack[i - 2], expr)); - i -= 2; - } - } - return expr; - }; - // https://tc39.github.io/ecma262/#sec-conditional-operator - Parser.prototype.parseConditionalExpression = function () { - var startToken = this.lookahead; - var expr = this.inheritCoverGrammar(this.parseBinaryExpression); - if (this.match('?')) { - this.nextToken(); - var previousAllowIn = this.context.allowIn; - this.context.allowIn = true; - var consequent = this.isolateCoverGrammar(this.parseAssignmentExpression); - this.context.allowIn = previousAllowIn; - this.expect(':'); - var alternate = this.isolateCoverGrammar(this.parseAssignmentExpression); - expr = this.finalize(this.startNode(startToken), new Node.ConditionalExpression(expr, consequent, alternate)); - this.context.isAssignmentTarget = false; - this.context.isBindingElement = false; - } - return expr; - }; - // https://tc39.github.io/ecma262/#sec-assignment-operators - Parser.prototype.checkPatternParam = function (options, param) { - switch (param.type) { - case syntax_1.Syntax.Identifier: - this.validateParam(options, param, param.name); - break; - case syntax_1.Syntax.RestElement: - this.checkPatternParam(options, param.argument); - break; - case syntax_1.Syntax.AssignmentPattern: - this.checkPatternParam(options, param.left); - break; - case syntax_1.Syntax.ArrayPattern: - for (var i = 0; i < param.elements.length; i++) { - if (param.elements[i] !== null) { - this.checkPatternParam(options, param.elements[i]); - } - } - break; - case syntax_1.Syntax.ObjectPattern: - for (var i = 0; i < param.properties.length; i++) { - this.checkPatternParam(options, param.properties[i].value); - } - break; - default: - break; - } - options.simple = options.simple && (param instanceof Node.Identifier); - }; - Parser.prototype.reinterpretAsCoverFormalsList = function (expr) { - var params = [expr]; - var options; - var asyncArrow = false; - switch (expr.type) { - case syntax_1.Syntax.Identifier: - break; - case ArrowParameterPlaceHolder: - params = expr.params; - asyncArrow = expr.async; - break; - default: - return null; - } - options = { - simple: true, - paramSet: {} - }; - for (var i = 0; i < params.length; ++i) { - var param = params[i]; - if (param.type === syntax_1.Syntax.AssignmentPattern) { - if (param.right.type === syntax_1.Syntax.YieldExpression) { - if (param.right.argument) { - this.throwUnexpectedToken(this.lookahead); - } - param.right.type = syntax_1.Syntax.Identifier; - param.right.name = 'yield'; - delete param.right.argument; - delete param.right.delegate; - } - } - else if (asyncArrow && param.type === syntax_1.Syntax.Identifier && param.name === 'await') { - this.throwUnexpectedToken(this.lookahead); - } - this.checkPatternParam(options, param); - params[i] = param; - } - if (this.context.strict || !this.context.allowYield) { - for (var i = 0; i < params.length; ++i) { - var param = params[i]; - if (param.type === syntax_1.Syntax.YieldExpression) { - this.throwUnexpectedToken(this.lookahead); - } - } - } - if (options.message === messages_1.Messages.StrictParamDupe) { - var token = this.context.strict ? options.stricted : options.firstRestricted; - this.throwUnexpectedToken(token, options.message); - } - return { - simple: options.simple, - params: params, - stricted: options.stricted, - firstRestricted: options.firstRestricted, - message: options.message - }; - }; - Parser.prototype.parseAssignmentExpression = function () { - var expr; - if (!this.context.allowYield && this.matchKeyword('yield')) { - expr = this.parseYieldExpression(); - } - else { - var startToken = this.lookahead; - var token = startToken; - expr = this.parseConditionalExpression(); - if (token.type === 3 /* Identifier */ && (token.lineNumber === this.lookahead.lineNumber) && token.value === 'async') { - if (this.lookahead.type === 3 /* Identifier */ || this.matchKeyword('yield')) { - var arg = this.parsePrimaryExpression(); - this.reinterpretExpressionAsPattern(arg); - expr = { - type: ArrowParameterPlaceHolder, - params: [arg], - async: true - }; - } - } - if (expr.type === ArrowParameterPlaceHolder || this.match('=>')) { - // https://tc39.github.io/ecma262/#sec-arrow-function-definitions - this.context.isAssignmentTarget = false; - this.context.isBindingElement = false; - var isAsync = expr.async; - var list = this.reinterpretAsCoverFormalsList(expr); - if (list) { - if (this.hasLineTerminator) { - this.tolerateUnexpectedToken(this.lookahead); - } - this.context.firstCoverInitializedNameError = null; - var previousStrict = this.context.strict; - var previousAllowStrictDirective = this.context.allowStrictDirective; - this.context.allowStrictDirective = list.simple; - var previousAllowYield = this.context.allowYield; - var previousAwait = this.context.await; - this.context.allowYield = true; - this.context.await = isAsync; - var node = this.startNode(startToken); - this.expect('=>'); - var body = void 0; - if (this.match('{')) { - var previousAllowIn = this.context.allowIn; - this.context.allowIn = true; - body = this.parseFunctionSourceElements(); - this.context.allowIn = previousAllowIn; - } - else { - body = this.isolateCoverGrammar(this.parseAssignmentExpression); - } - var expression = body.type !== syntax_1.Syntax.BlockStatement; - if (this.context.strict && list.firstRestricted) { - this.throwUnexpectedToken(list.firstRestricted, list.message); - } - if (this.context.strict && list.stricted) { - this.tolerateUnexpectedToken(list.stricted, list.message); - } - expr = isAsync ? this.finalize(node, new Node.AsyncArrowFunctionExpression(list.params, body, expression)) : - this.finalize(node, new Node.ArrowFunctionExpression(list.params, body, expression)); - this.context.strict = previousStrict; - this.context.allowStrictDirective = previousAllowStrictDirective; - this.context.allowYield = previousAllowYield; - this.context.await = previousAwait; - } - } - else { - if (this.matchAssign()) { - if (!this.context.isAssignmentTarget) { - this.tolerateError(messages_1.Messages.InvalidLHSInAssignment); - } - if (this.context.strict && expr.type === syntax_1.Syntax.Identifier) { - var id = expr; - if (this.scanner.isRestrictedWord(id.name)) { - this.tolerateUnexpectedToken(token, messages_1.Messages.StrictLHSAssignment); - } - if (this.scanner.isStrictModeReservedWord(id.name)) { - this.tolerateUnexpectedToken(token, messages_1.Messages.StrictReservedWord); - } - } - if (!this.match('=')) { - this.context.isAssignmentTarget = false; - this.context.isBindingElement = false; - } - else { - this.reinterpretExpressionAsPattern(expr); - } - token = this.nextToken(); - var operator = token.value; - var right = this.isolateCoverGrammar(this.parseAssignmentExpression); - expr = this.finalize(this.startNode(startToken), new Node.AssignmentExpression(operator, expr, right)); - this.context.firstCoverInitializedNameError = null; - } - } - } - return expr; - }; - // https://tc39.github.io/ecma262/#sec-comma-operator - Parser.prototype.parseExpression = function () { - var startToken = this.lookahead; - var expr = this.isolateCoverGrammar(this.parseAssignmentExpression); - if (this.match(',')) { - var expressions = []; - expressions.push(expr); - while (this.lookahead.type !== 2 /* EOF */) { - if (!this.match(',')) { - break; - } - this.nextToken(); - expressions.push(this.isolateCoverGrammar(this.parseAssignmentExpression)); - } - expr = this.finalize(this.startNode(startToken), new Node.SequenceExpression(expressions)); - } - return expr; - }; - // https://tc39.github.io/ecma262/#sec-block - Parser.prototype.parseStatementListItem = function () { - var statement; - this.context.isAssignmentTarget = true; - this.context.isBindingElement = true; - if (this.lookahead.type === 4 /* Keyword */) { - switch (this.lookahead.value) { - case 'export': - if (!this.context.isModule) { - this.tolerateUnexpectedToken(this.lookahead, messages_1.Messages.IllegalExportDeclaration); - } - statement = this.parseExportDeclaration(); - break; - case 'import': - if (!this.context.isModule) { - this.tolerateUnexpectedToken(this.lookahead, messages_1.Messages.IllegalImportDeclaration); - } - statement = this.parseImportDeclaration(); - break; - case 'const': - statement = this.parseLexicalDeclaration({ inFor: false }); - break; - case 'function': - statement = this.parseFunctionDeclaration(); - break; - case 'class': - statement = this.parseClassDeclaration(); - break; - case 'let': - statement = this.isLexicalDeclaration() ? this.parseLexicalDeclaration({ inFor: false }) : this.parseStatement(); - break; - default: - statement = this.parseStatement(); - break; - } - } - else { - statement = this.parseStatement(); - } - return statement; - }; - Parser.prototype.parseBlock = function () { - var node = this.createNode(); - this.expect('{'); - var block = []; - while (true) { - if (this.match('}')) { - break; - } - block.push(this.parseStatementListItem()); - } - this.expect('}'); - return this.finalize(node, new Node.BlockStatement(block)); - }; - // https://tc39.github.io/ecma262/#sec-let-and-const-declarations - Parser.prototype.parseLexicalBinding = function (kind, options) { - var node = this.createNode(); - var params = []; - var id = this.parsePattern(params, kind); - if (this.context.strict && id.type === syntax_1.Syntax.Identifier) { - if (this.scanner.isRestrictedWord(id.name)) { - this.tolerateError(messages_1.Messages.StrictVarName); - } - } - var init = null; - if (kind === 'const') { - if (!this.matchKeyword('in') && !this.matchContextualKeyword('of')) { - if (this.match('=')) { - this.nextToken(); - init = this.isolateCoverGrammar(this.parseAssignmentExpression); - } - else { - this.throwError(messages_1.Messages.DeclarationMissingInitializer, 'const'); - } - } - } - else if ((!options.inFor && id.type !== syntax_1.Syntax.Identifier) || this.match('=')) { - this.expect('='); - init = this.isolateCoverGrammar(this.parseAssignmentExpression); - } - return this.finalize(node, new Node.VariableDeclarator(id, init)); - }; - Parser.prototype.parseBindingList = function (kind, options) { - var list = [this.parseLexicalBinding(kind, options)]; - while (this.match(',')) { - this.nextToken(); - list.push(this.parseLexicalBinding(kind, options)); - } - return list; - }; - Parser.prototype.isLexicalDeclaration = function () { - var state = this.scanner.saveState(); - this.scanner.scanComments(); - var next = this.scanner.lex(); - this.scanner.restoreState(state); - return (next.type === 3 /* Identifier */) || - (next.type === 7 /* Punctuator */ && next.value === '[') || - (next.type === 7 /* Punctuator */ && next.value === '{') || - (next.type === 4 /* Keyword */ && next.value === 'let') || - (next.type === 4 /* Keyword */ && next.value === 'yield'); - }; - Parser.prototype.parseLexicalDeclaration = function (options) { - var node = this.createNode(); - var kind = this.nextToken().value; - assert_1.assert(kind === 'let' || kind === 'const', 'Lexical declaration must be either let or const'); - var declarations = this.parseBindingList(kind, options); - this.consumeSemicolon(); - return this.finalize(node, new Node.VariableDeclaration(declarations, kind)); - }; - // https://tc39.github.io/ecma262/#sec-destructuring-binding-patterns - Parser.prototype.parseBindingRestElement = function (params, kind) { - var node = this.createNode(); - this.expect('...'); - var arg = this.parsePattern(params, kind); - return this.finalize(node, new Node.RestElement(arg)); - }; - Parser.prototype.parseArrayPattern = function (params, kind) { - var node = this.createNode(); - this.expect('['); - var elements = []; - while (!this.match(']')) { - if (this.match(',')) { - this.nextToken(); - elements.push(null); - } - else { - if (this.match('...')) { - elements.push(this.parseBindingRestElement(params, kind)); - break; - } - else { - elements.push(this.parsePatternWithDefault(params, kind)); - } - if (!this.match(']')) { - this.expect(','); - } - } - } - this.expect(']'); - return this.finalize(node, new Node.ArrayPattern(elements)); - }; - Parser.prototype.parsePropertyPattern = function (params, kind) { - var node = this.createNode(); - var computed = false; - var shorthand = false; - var method = false; - var key; - var value; - if (this.lookahead.type === 3 /* Identifier */) { - var keyToken = this.lookahead; - key = this.parseVariableIdentifier(); - var init = this.finalize(node, new Node.Identifier(keyToken.value)); - if (this.match('=')) { - params.push(keyToken); - shorthand = true; - this.nextToken(); - var expr = this.parseAssignmentExpression(); - value = this.finalize(this.startNode(keyToken), new Node.AssignmentPattern(init, expr)); - } - else if (!this.match(':')) { - params.push(keyToken); - shorthand = true; - value = init; - } - else { - this.expect(':'); - value = this.parsePatternWithDefault(params, kind); - } - } - else { - computed = this.match('['); - key = this.parseObjectPropertyKey(); - this.expect(':'); - value = this.parsePatternWithDefault(params, kind); - } - return this.finalize(node, new Node.Property('init', key, computed, value, method, shorthand)); - }; - Parser.prototype.parseObjectPattern = function (params, kind) { - var node = this.createNode(); - var properties = []; - this.expect('{'); - while (!this.match('}')) { - properties.push(this.parsePropertyPattern(params, kind)); - if (!this.match('}')) { - this.expect(','); - } - } - this.expect('}'); - return this.finalize(node, new Node.ObjectPattern(properties)); - }; - Parser.prototype.parsePattern = function (params, kind) { - var pattern; - if (this.match('[')) { - pattern = this.parseArrayPattern(params, kind); - } - else if (this.match('{')) { - pattern = this.parseObjectPattern(params, kind); - } - else { - if (this.matchKeyword('let') && (kind === 'const' || kind === 'let')) { - this.tolerateUnexpectedToken(this.lookahead, messages_1.Messages.LetInLexicalBinding); - } - params.push(this.lookahead); - pattern = this.parseVariableIdentifier(kind); - } - return pattern; - }; - Parser.prototype.parsePatternWithDefault = function (params, kind) { - var startToken = this.lookahead; - var pattern = this.parsePattern(params, kind); - if (this.match('=')) { - this.nextToken(); - var previousAllowYield = this.context.allowYield; - this.context.allowYield = true; - var right = this.isolateCoverGrammar(this.parseAssignmentExpression); - this.context.allowYield = previousAllowYield; - pattern = this.finalize(this.startNode(startToken), new Node.AssignmentPattern(pattern, right)); - } - return pattern; - }; - // https://tc39.github.io/ecma262/#sec-variable-statement - Parser.prototype.parseVariableIdentifier = function (kind) { - var node = this.createNode(); - var token = this.nextToken(); - if (token.type === 4 /* Keyword */ && token.value === 'yield') { - if (this.context.strict) { - this.tolerateUnexpectedToken(token, messages_1.Messages.StrictReservedWord); - } - else if (!this.context.allowYield) { - this.throwUnexpectedToken(token); - } - } - else if (token.type !== 3 /* Identifier */) { - if (this.context.strict && token.type === 4 /* Keyword */ && this.scanner.isStrictModeReservedWord(token.value)) { - this.tolerateUnexpectedToken(token, messages_1.Messages.StrictReservedWord); - } - else { - if (this.context.strict || token.value !== 'let' || kind !== 'var') { - this.throwUnexpectedToken(token); - } - } - } - else if ((this.context.isModule || this.context.await) && token.type === 3 /* Identifier */ && token.value === 'await') { - this.tolerateUnexpectedToken(token); - } - return this.finalize(node, new Node.Identifier(token.value)); - }; - Parser.prototype.parseVariableDeclaration = function (options) { - var node = this.createNode(); - var params = []; - var id = this.parsePattern(params, 'var'); - if (this.context.strict && id.type === syntax_1.Syntax.Identifier) { - if (this.scanner.isRestrictedWord(id.name)) { - this.tolerateError(messages_1.Messages.StrictVarName); - } - } - var init = null; - if (this.match('=')) { - this.nextToken(); - init = this.isolateCoverGrammar(this.parseAssignmentExpression); - } - else if (id.type !== syntax_1.Syntax.Identifier && !options.inFor) { - this.expect('='); - } - return this.finalize(node, new Node.VariableDeclarator(id, init)); - }; - Parser.prototype.parseVariableDeclarationList = function (options) { - var opt = { inFor: options.inFor }; - var list = []; - list.push(this.parseVariableDeclaration(opt)); - while (this.match(',')) { - this.nextToken(); - list.push(this.parseVariableDeclaration(opt)); - } - return list; - }; - Parser.prototype.parseVariableStatement = function () { - var node = this.createNode(); - this.expectKeyword('var'); - var declarations = this.parseVariableDeclarationList({ inFor: false }); - this.consumeSemicolon(); - return this.finalize(node, new Node.VariableDeclaration(declarations, 'var')); - }; - // https://tc39.github.io/ecma262/#sec-empty-statement - Parser.prototype.parseEmptyStatement = function () { - var node = this.createNode(); - this.expect(';'); - return this.finalize(node, new Node.EmptyStatement()); - }; - // https://tc39.github.io/ecma262/#sec-expression-statement - Parser.prototype.parseExpressionStatement = function () { - var node = this.createNode(); - var expr = this.parseExpression(); - this.consumeSemicolon(); - return this.finalize(node, new Node.ExpressionStatement(expr)); - }; - // https://tc39.github.io/ecma262/#sec-if-statement - Parser.prototype.parseIfClause = function () { - if (this.context.strict && this.matchKeyword('function')) { - this.tolerateError(messages_1.Messages.StrictFunction); - } - return this.parseStatement(); - }; - Parser.prototype.parseIfStatement = function () { - var node = this.createNode(); - var consequent; - var alternate = null; - this.expectKeyword('if'); - this.expect('('); - var test = this.parseExpression(); - if (!this.match(')') && this.config.tolerant) { - this.tolerateUnexpectedToken(this.nextToken()); - consequent = this.finalize(this.createNode(), new Node.EmptyStatement()); - } - else { - this.expect(')'); - consequent = this.parseIfClause(); - if (this.matchKeyword('else')) { - this.nextToken(); - alternate = this.parseIfClause(); - } - } - return this.finalize(node, new Node.IfStatement(test, consequent, alternate)); - }; - // https://tc39.github.io/ecma262/#sec-do-while-statement - Parser.prototype.parseDoWhileStatement = function () { - var node = this.createNode(); - this.expectKeyword('do'); - var previousInIteration = this.context.inIteration; - this.context.inIteration = true; - var body = this.parseStatement(); - this.context.inIteration = previousInIteration; - this.expectKeyword('while'); - this.expect('('); - var test = this.parseExpression(); - if (!this.match(')') && this.config.tolerant) { - this.tolerateUnexpectedToken(this.nextToken()); - } - else { - this.expect(')'); - if (this.match(';')) { - this.nextToken(); - } - } - return this.finalize(node, new Node.DoWhileStatement(body, test)); - }; - // https://tc39.github.io/ecma262/#sec-while-statement - Parser.prototype.parseWhileStatement = function () { - var node = this.createNode(); - var body; - this.expectKeyword('while'); - this.expect('('); - var test = this.parseExpression(); - if (!this.match(')') && this.config.tolerant) { - this.tolerateUnexpectedToken(this.nextToken()); - body = this.finalize(this.createNode(), new Node.EmptyStatement()); - } - else { - this.expect(')'); - var previousInIteration = this.context.inIteration; - this.context.inIteration = true; - body = this.parseStatement(); - this.context.inIteration = previousInIteration; - } - return this.finalize(node, new Node.WhileStatement(test, body)); - }; - // https://tc39.github.io/ecma262/#sec-for-statement - // https://tc39.github.io/ecma262/#sec-for-in-and-for-of-statements - Parser.prototype.parseForStatement = function () { - var init = null; - var test = null; - var update = null; - var forIn = true; - var left, right; - var node = this.createNode(); - this.expectKeyword('for'); - this.expect('('); - if (this.match(';')) { - this.nextToken(); - } - else { - if (this.matchKeyword('var')) { - init = this.createNode(); - this.nextToken(); - var previousAllowIn = this.context.allowIn; - this.context.allowIn = false; - var declarations = this.parseVariableDeclarationList({ inFor: true }); - this.context.allowIn = previousAllowIn; - if (declarations.length === 1 && this.matchKeyword('in')) { - var decl = declarations[0]; - if (decl.init && (decl.id.type === syntax_1.Syntax.ArrayPattern || decl.id.type === syntax_1.Syntax.ObjectPattern || this.context.strict)) { - this.tolerateError(messages_1.Messages.ForInOfLoopInitializer, 'for-in'); - } - init = this.finalize(init, new Node.VariableDeclaration(declarations, 'var')); - this.nextToken(); - left = init; - right = this.parseExpression(); - init = null; - } - else if (declarations.length === 1 && declarations[0].init === null && this.matchContextualKeyword('of')) { - init = this.finalize(init, new Node.VariableDeclaration(declarations, 'var')); - this.nextToken(); - left = init; - right = this.parseAssignmentExpression(); - init = null; - forIn = false; - } - else { - init = this.finalize(init, new Node.VariableDeclaration(declarations, 'var')); - this.expect(';'); - } - } - else if (this.matchKeyword('const') || this.matchKeyword('let')) { - init = this.createNode(); - var kind = this.nextToken().value; - if (!this.context.strict && this.lookahead.value === 'in') { - init = this.finalize(init, new Node.Identifier(kind)); - this.nextToken(); - left = init; - right = this.parseExpression(); - init = null; - } - else { - var previousAllowIn = this.context.allowIn; - this.context.allowIn = false; - var declarations = this.parseBindingList(kind, { inFor: true }); - this.context.allowIn = previousAllowIn; - if (declarations.length === 1 && declarations[0].init === null && this.matchKeyword('in')) { - init = this.finalize(init, new Node.VariableDeclaration(declarations, kind)); - this.nextToken(); - left = init; - right = this.parseExpression(); - init = null; - } - else if (declarations.length === 1 && declarations[0].init === null && this.matchContextualKeyword('of')) { - init = this.finalize(init, new Node.VariableDeclaration(declarations, kind)); - this.nextToken(); - left = init; - right = this.parseAssignmentExpression(); - init = null; - forIn = false; - } - else { - this.consumeSemicolon(); - init = this.finalize(init, new Node.VariableDeclaration(declarations, kind)); - } - } - } - else { - var initStartToken = this.lookahead; - var previousAllowIn = this.context.allowIn; - this.context.allowIn = false; - init = this.inheritCoverGrammar(this.parseAssignmentExpression); - this.context.allowIn = previousAllowIn; - if (this.matchKeyword('in')) { - if (!this.context.isAssignmentTarget || init.type === syntax_1.Syntax.AssignmentExpression) { - this.tolerateError(messages_1.Messages.InvalidLHSInForIn); - } - this.nextToken(); - this.reinterpretExpressionAsPattern(init); - left = init; - right = this.parseExpression(); - init = null; - } - else if (this.matchContextualKeyword('of')) { - if (!this.context.isAssignmentTarget || init.type === syntax_1.Syntax.AssignmentExpression) { - this.tolerateError(messages_1.Messages.InvalidLHSInForLoop); - } - this.nextToken(); - this.reinterpretExpressionAsPattern(init); - left = init; - right = this.parseAssignmentExpression(); - init = null; - forIn = false; - } - else { - if (this.match(',')) { - var initSeq = [init]; - while (this.match(',')) { - this.nextToken(); - initSeq.push(this.isolateCoverGrammar(this.parseAssignmentExpression)); - } - init = this.finalize(this.startNode(initStartToken), new Node.SequenceExpression(initSeq)); - } - this.expect(';'); - } - } - } - if (typeof left === 'undefined') { - if (!this.match(';')) { - test = this.parseExpression(); - } - this.expect(';'); - if (!this.match(')')) { - update = this.parseExpression(); - } - } - var body; - if (!this.match(')') && this.config.tolerant) { - this.tolerateUnexpectedToken(this.nextToken()); - body = this.finalize(this.createNode(), new Node.EmptyStatement()); - } - else { - this.expect(')'); - var previousInIteration = this.context.inIteration; - this.context.inIteration = true; - body = this.isolateCoverGrammar(this.parseStatement); - this.context.inIteration = previousInIteration; - } - return (typeof left === 'undefined') ? - this.finalize(node, new Node.ForStatement(init, test, update, body)) : - forIn ? this.finalize(node, new Node.ForInStatement(left, right, body)) : - this.finalize(node, new Node.ForOfStatement(left, right, body)); - }; - // https://tc39.github.io/ecma262/#sec-continue-statement - Parser.prototype.parseContinueStatement = function () { - var node = this.createNode(); - this.expectKeyword('continue'); - var label = null; - if (this.lookahead.type === 3 /* Identifier */ && !this.hasLineTerminator) { - var id = this.parseVariableIdentifier(); - label = id; - var key = '$' + id.name; - if (!Object.prototype.hasOwnProperty.call(this.context.labelSet, key)) { - this.throwError(messages_1.Messages.UnknownLabel, id.name); - } - } - this.consumeSemicolon(); - if (label === null && !this.context.inIteration) { - this.throwError(messages_1.Messages.IllegalContinue); - } - return this.finalize(node, new Node.ContinueStatement(label)); - }; - // https://tc39.github.io/ecma262/#sec-break-statement - Parser.prototype.parseBreakStatement = function () { - var node = this.createNode(); - this.expectKeyword('break'); - var label = null; - if (this.lookahead.type === 3 /* Identifier */ && !this.hasLineTerminator) { - var id = this.parseVariableIdentifier(); - var key = '$' + id.name; - if (!Object.prototype.hasOwnProperty.call(this.context.labelSet, key)) { - this.throwError(messages_1.Messages.UnknownLabel, id.name); - } - label = id; - } - this.consumeSemicolon(); - if (label === null && !this.context.inIteration && !this.context.inSwitch) { - this.throwError(messages_1.Messages.IllegalBreak); - } - return this.finalize(node, new Node.BreakStatement(label)); - }; - // https://tc39.github.io/ecma262/#sec-return-statement - Parser.prototype.parseReturnStatement = function () { - if (!this.context.inFunctionBody) { - this.tolerateError(messages_1.Messages.IllegalReturn); - } - var node = this.createNode(); - this.expectKeyword('return'); - var hasArgument = !this.match(';') && !this.match('}') && - !this.hasLineTerminator && this.lookahead.type !== 2 /* EOF */; - var argument = hasArgument ? this.parseExpression() : null; - this.consumeSemicolon(); - return this.finalize(node, new Node.ReturnStatement(argument)); - }; - // https://tc39.github.io/ecma262/#sec-with-statement - Parser.prototype.parseWithStatement = function () { - if (this.context.strict) { - this.tolerateError(messages_1.Messages.StrictModeWith); - } - var node = this.createNode(); - var body; - this.expectKeyword('with'); - this.expect('('); - var object = this.parseExpression(); - if (!this.match(')') && this.config.tolerant) { - this.tolerateUnexpectedToken(this.nextToken()); - body = this.finalize(this.createNode(), new Node.EmptyStatement()); - } - else { - this.expect(')'); - body = this.parseStatement(); - } - return this.finalize(node, new Node.WithStatement(object, body)); - }; - // https://tc39.github.io/ecma262/#sec-switch-statement - Parser.prototype.parseSwitchCase = function () { - var node = this.createNode(); - var test; - if (this.matchKeyword('default')) { - this.nextToken(); - test = null; - } - else { - this.expectKeyword('case'); - test = this.parseExpression(); - } - this.expect(':'); - var consequent = []; - while (true) { - if (this.match('}') || this.matchKeyword('default') || this.matchKeyword('case')) { - break; - } - consequent.push(this.parseStatementListItem()); - } - return this.finalize(node, new Node.SwitchCase(test, consequent)); - }; - Parser.prototype.parseSwitchStatement = function () { - var node = this.createNode(); - this.expectKeyword('switch'); - this.expect('('); - var discriminant = this.parseExpression(); - this.expect(')'); - var previousInSwitch = this.context.inSwitch; - this.context.inSwitch = true; - var cases = []; - var defaultFound = false; - this.expect('{'); - while (true) { - if (this.match('}')) { - break; - } - var clause = this.parseSwitchCase(); - if (clause.test === null) { - if (defaultFound) { - this.throwError(messages_1.Messages.MultipleDefaultsInSwitch); - } - defaultFound = true; - } - cases.push(clause); - } - this.expect('}'); - this.context.inSwitch = previousInSwitch; - return this.finalize(node, new Node.SwitchStatement(discriminant, cases)); - }; - // https://tc39.github.io/ecma262/#sec-labelled-statements - Parser.prototype.parseLabelledStatement = function () { - var node = this.createNode(); - var expr = this.parseExpression(); - var statement; - if ((expr.type === syntax_1.Syntax.Identifier) && this.match(':')) { - this.nextToken(); - var id = expr; - var key = '$' + id.name; - if (Object.prototype.hasOwnProperty.call(this.context.labelSet, key)) { - this.throwError(messages_1.Messages.Redeclaration, 'Label', id.name); - } - this.context.labelSet[key] = true; - var body = void 0; - if (this.matchKeyword('class')) { - this.tolerateUnexpectedToken(this.lookahead); - body = this.parseClassDeclaration(); - } - else if (this.matchKeyword('function')) { - var token = this.lookahead; - var declaration = this.parseFunctionDeclaration(); - if (this.context.strict) { - this.tolerateUnexpectedToken(token, messages_1.Messages.StrictFunction); - } - else if (declaration.generator) { - this.tolerateUnexpectedToken(token, messages_1.Messages.GeneratorInLegacyContext); - } - body = declaration; - } - else { - body = this.parseStatement(); - } - delete this.context.labelSet[key]; - statement = new Node.LabeledStatement(id, body); - } - else { - this.consumeSemicolon(); - statement = new Node.ExpressionStatement(expr); - } - return this.finalize(node, statement); - }; - // https://tc39.github.io/ecma262/#sec-throw-statement - Parser.prototype.parseThrowStatement = function () { - var node = this.createNode(); - this.expectKeyword('throw'); - if (this.hasLineTerminator) { - this.throwError(messages_1.Messages.NewlineAfterThrow); - } - var argument = this.parseExpression(); - this.consumeSemicolon(); - return this.finalize(node, new Node.ThrowStatement(argument)); - }; - // https://tc39.github.io/ecma262/#sec-try-statement - Parser.prototype.parseCatchClause = function () { - var node = this.createNode(); - this.expectKeyword('catch'); - this.expect('('); - if (this.match(')')) { - this.throwUnexpectedToken(this.lookahead); - } - var params = []; - var param = this.parsePattern(params); - var paramMap = {}; - for (var i = 0; i < params.length; i++) { - var key = '$' + params[i].value; - if (Object.prototype.hasOwnProperty.call(paramMap, key)) { - this.tolerateError(messages_1.Messages.DuplicateBinding, params[i].value); - } - paramMap[key] = true; - } - if (this.context.strict && param.type === syntax_1.Syntax.Identifier) { - if (this.scanner.isRestrictedWord(param.name)) { - this.tolerateError(messages_1.Messages.StrictCatchVariable); - } - } - this.expect(')'); - var body = this.parseBlock(); - return this.finalize(node, new Node.CatchClause(param, body)); - }; - Parser.prototype.parseFinallyClause = function () { - this.expectKeyword('finally'); - return this.parseBlock(); - }; - Parser.prototype.parseTryStatement = function () { - var node = this.createNode(); - this.expectKeyword('try'); - var block = this.parseBlock(); - var handler = this.matchKeyword('catch') ? this.parseCatchClause() : null; - var finalizer = this.matchKeyword('finally') ? this.parseFinallyClause() : null; - if (!handler && !finalizer) { - this.throwError(messages_1.Messages.NoCatchOrFinally); - } - return this.finalize(node, new Node.TryStatement(block, handler, finalizer)); - }; - // https://tc39.github.io/ecma262/#sec-debugger-statement - Parser.prototype.parseDebuggerStatement = function () { - var node = this.createNode(); - this.expectKeyword('debugger'); - this.consumeSemicolon(); - return this.finalize(node, new Node.DebuggerStatement()); - }; - // https://tc39.github.io/ecma262/#sec-ecmascript-language-statements-and-declarations - Parser.prototype.parseStatement = function () { - var statement; - switch (this.lookahead.type) { - case 1 /* BooleanLiteral */: - case 5 /* NullLiteral */: - case 6 /* NumericLiteral */: - case 8 /* StringLiteral */: - case 10 /* Template */: - case 9 /* RegularExpression */: - statement = this.parseExpressionStatement(); - break; - case 7 /* Punctuator */: - var value = this.lookahead.value; - if (value === '{') { - statement = this.parseBlock(); - } - else if (value === '(') { - statement = this.parseExpressionStatement(); - } - else if (value === ';') { - statement = this.parseEmptyStatement(); - } - else { - statement = this.parseExpressionStatement(); - } - break; - case 3 /* Identifier */: - statement = this.matchAsyncFunction() ? this.parseFunctionDeclaration() : this.parseLabelledStatement(); - break; - case 4 /* Keyword */: - switch (this.lookahead.value) { - case 'break': - statement = this.parseBreakStatement(); - break; - case 'continue': - statement = this.parseContinueStatement(); - break; - case 'debugger': - statement = this.parseDebuggerStatement(); - break; - case 'do': - statement = this.parseDoWhileStatement(); - break; - case 'for': - statement = this.parseForStatement(); - break; - case 'function': - statement = this.parseFunctionDeclaration(); - break; - case 'if': - statement = this.parseIfStatement(); - break; - case 'return': - statement = this.parseReturnStatement(); - break; - case 'switch': - statement = this.parseSwitchStatement(); - break; - case 'throw': - statement = this.parseThrowStatement(); - break; - case 'try': - statement = this.parseTryStatement(); - break; - case 'var': - statement = this.parseVariableStatement(); - break; - case 'while': - statement = this.parseWhileStatement(); - break; - case 'with': - statement = this.parseWithStatement(); - break; - default: - statement = this.parseExpressionStatement(); - break; - } - break; - default: - statement = this.throwUnexpectedToken(this.lookahead); - } - return statement; - }; - // https://tc39.github.io/ecma262/#sec-function-definitions - Parser.prototype.parseFunctionSourceElements = function () { - var node = this.createNode(); - this.expect('{'); - var body = this.parseDirectivePrologues(); - var previousLabelSet = this.context.labelSet; - var previousInIteration = this.context.inIteration; - var previousInSwitch = this.context.inSwitch; - var previousInFunctionBody = this.context.inFunctionBody; - this.context.labelSet = {}; - this.context.inIteration = false; - this.context.inSwitch = false; - this.context.inFunctionBody = true; - while (this.lookahead.type !== 2 /* EOF */) { - if (this.match('}')) { - break; - } - body.push(this.parseStatementListItem()); - } - this.expect('}'); - this.context.labelSet = previousLabelSet; - this.context.inIteration = previousInIteration; - this.context.inSwitch = previousInSwitch; - this.context.inFunctionBody = previousInFunctionBody; - return this.finalize(node, new Node.BlockStatement(body)); - }; - Parser.prototype.validateParam = function (options, param, name) { - var key = '$' + name; - if (this.context.strict) { - if (this.scanner.isRestrictedWord(name)) { - options.stricted = param; - options.message = messages_1.Messages.StrictParamName; - } - if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) { - options.stricted = param; - options.message = messages_1.Messages.StrictParamDupe; - } - } - else if (!options.firstRestricted) { - if (this.scanner.isRestrictedWord(name)) { - options.firstRestricted = param; - options.message = messages_1.Messages.StrictParamName; - } - else if (this.scanner.isStrictModeReservedWord(name)) { - options.firstRestricted = param; - options.message = messages_1.Messages.StrictReservedWord; - } - else if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) { - options.stricted = param; - options.message = messages_1.Messages.StrictParamDupe; - } - } - /* istanbul ignore next */ - if (typeof Object.defineProperty === 'function') { - Object.defineProperty(options.paramSet, key, { value: true, enumerable: true, writable: true, configurable: true }); - } - else { - options.paramSet[key] = true; - } - }; - Parser.prototype.parseRestElement = function (params) { - var node = this.createNode(); - this.expect('...'); - var arg = this.parsePattern(params); - if (this.match('=')) { - this.throwError(messages_1.Messages.DefaultRestParameter); - } - if (!this.match(')')) { - this.throwError(messages_1.Messages.ParameterAfterRestParameter); - } - return this.finalize(node, new Node.RestElement(arg)); - }; - Parser.prototype.parseFormalParameter = function (options) { - var params = []; - var param = this.match('...') ? this.parseRestElement(params) : this.parsePatternWithDefault(params); - for (var i = 0; i < params.length; i++) { - this.validateParam(options, params[i], params[i].value); - } - options.simple = options.simple && (param instanceof Node.Identifier); - options.params.push(param); - }; - Parser.prototype.parseFormalParameters = function (firstRestricted) { - var options; - options = { - simple: true, - params: [], - firstRestricted: firstRestricted - }; - this.expect('('); - if (!this.match(')')) { - options.paramSet = {}; - while (this.lookahead.type !== 2 /* EOF */) { - this.parseFormalParameter(options); - if (this.match(')')) { - break; - } - this.expect(','); - if (this.match(')')) { - break; - } - } - } - this.expect(')'); - return { - simple: options.simple, - params: options.params, - stricted: options.stricted, - firstRestricted: options.firstRestricted, - message: options.message - }; - }; - Parser.prototype.matchAsyncFunction = function () { - var match = this.matchContextualKeyword('async'); - if (match) { - var state = this.scanner.saveState(); - this.scanner.scanComments(); - var next = this.scanner.lex(); - this.scanner.restoreState(state); - match = (state.lineNumber === next.lineNumber) && (next.type === 4 /* Keyword */) && (next.value === 'function'); - } - return match; - }; - Parser.prototype.parseFunctionDeclaration = function (identifierIsOptional) { - var node = this.createNode(); - var isAsync = this.matchContextualKeyword('async'); - if (isAsync) { - this.nextToken(); - } - this.expectKeyword('function'); - var isGenerator = isAsync ? false : this.match('*'); - if (isGenerator) { - this.nextToken(); - } - var message; - var id = null; - var firstRestricted = null; - if (!identifierIsOptional || !this.match('(')) { - var token = this.lookahead; - id = this.parseVariableIdentifier(); - if (this.context.strict) { - if (this.scanner.isRestrictedWord(token.value)) { - this.tolerateUnexpectedToken(token, messages_1.Messages.StrictFunctionName); - } - } - else { - if (this.scanner.isRestrictedWord(token.value)) { - firstRestricted = token; - message = messages_1.Messages.StrictFunctionName; - } - else if (this.scanner.isStrictModeReservedWord(token.value)) { - firstRestricted = token; - message = messages_1.Messages.StrictReservedWord; - } - } - } - var previousAllowAwait = this.context.await; - var previousAllowYield = this.context.allowYield; - this.context.await = isAsync; - this.context.allowYield = !isGenerator; - var formalParameters = this.parseFormalParameters(firstRestricted); - var params = formalParameters.params; - var stricted = formalParameters.stricted; - firstRestricted = formalParameters.firstRestricted; - if (formalParameters.message) { - message = formalParameters.message; - } - var previousStrict = this.context.strict; - var previousAllowStrictDirective = this.context.allowStrictDirective; - this.context.allowStrictDirective = formalParameters.simple; - var body = this.parseFunctionSourceElements(); - if (this.context.strict && firstRestricted) { - this.throwUnexpectedToken(firstRestricted, message); - } - if (this.context.strict && stricted) { - this.tolerateUnexpectedToken(stricted, message); - } - this.context.strict = previousStrict; - this.context.allowStrictDirective = previousAllowStrictDirective; - this.context.await = previousAllowAwait; - this.context.allowYield = previousAllowYield; - return isAsync ? this.finalize(node, new Node.AsyncFunctionDeclaration(id, params, body)) : - this.finalize(node, new Node.FunctionDeclaration(id, params, body, isGenerator)); - }; - Parser.prototype.parseFunctionExpression = function () { - var node = this.createNode(); - var isAsync = this.matchContextualKeyword('async'); - if (isAsync) { - this.nextToken(); - } - this.expectKeyword('function'); - var isGenerator = isAsync ? false : this.match('*'); - if (isGenerator) { - this.nextToken(); - } - var message; - var id = null; - var firstRestricted; - var previousAllowAwait = this.context.await; - var previousAllowYield = this.context.allowYield; - this.context.await = isAsync; - this.context.allowYield = !isGenerator; - if (!this.match('(')) { - var token = this.lookahead; - id = (!this.context.strict && !isGenerator && this.matchKeyword('yield')) ? this.parseIdentifierName() : this.parseVariableIdentifier(); - if (this.context.strict) { - if (this.scanner.isRestrictedWord(token.value)) { - this.tolerateUnexpectedToken(token, messages_1.Messages.StrictFunctionName); - } - } - else { - if (this.scanner.isRestrictedWord(token.value)) { - firstRestricted = token; - message = messages_1.Messages.StrictFunctionName; - } - else if (this.scanner.isStrictModeReservedWord(token.value)) { - firstRestricted = token; - message = messages_1.Messages.StrictReservedWord; - } - } - } - var formalParameters = this.parseFormalParameters(firstRestricted); - var params = formalParameters.params; - var stricted = formalParameters.stricted; - firstRestricted = formalParameters.firstRestricted; - if (formalParameters.message) { - message = formalParameters.message; - } - var previousStrict = this.context.strict; - var previousAllowStrictDirective = this.context.allowStrictDirective; - this.context.allowStrictDirective = formalParameters.simple; - var body = this.parseFunctionSourceElements(); - if (this.context.strict && firstRestricted) { - this.throwUnexpectedToken(firstRestricted, message); - } - if (this.context.strict && stricted) { - this.tolerateUnexpectedToken(stricted, message); - } - this.context.strict = previousStrict; - this.context.allowStrictDirective = previousAllowStrictDirective; - this.context.await = previousAllowAwait; - this.context.allowYield = previousAllowYield; - return isAsync ? this.finalize(node, new Node.AsyncFunctionExpression(id, params, body)) : - this.finalize(node, new Node.FunctionExpression(id, params, body, isGenerator)); - }; - // https://tc39.github.io/ecma262/#sec-directive-prologues-and-the-use-strict-directive - Parser.prototype.parseDirective = function () { - var token = this.lookahead; - var node = this.createNode(); - var expr = this.parseExpression(); - var directive = (expr.type === syntax_1.Syntax.Literal) ? this.getTokenRaw(token).slice(1, -1) : null; - this.consumeSemicolon(); - return this.finalize(node, directive ? new Node.Directive(expr, directive) : new Node.ExpressionStatement(expr)); - }; - Parser.prototype.parseDirectivePrologues = function () { - var firstRestricted = null; - var body = []; - while (true) { - var token = this.lookahead; - if (token.type !== 8 /* StringLiteral */) { - break; - } - var statement = this.parseDirective(); - body.push(statement); - var directive = statement.directive; - if (typeof directive !== 'string') { - break; - } - if (directive === 'use strict') { - this.context.strict = true; - if (firstRestricted) { - this.tolerateUnexpectedToken(firstRestricted, messages_1.Messages.StrictOctalLiteral); - } - if (!this.context.allowStrictDirective) { - this.tolerateUnexpectedToken(token, messages_1.Messages.IllegalLanguageModeDirective); - } - } - else { - if (!firstRestricted && token.octal) { - firstRestricted = token; - } - } - } - return body; - }; - // https://tc39.github.io/ecma262/#sec-method-definitions - Parser.prototype.qualifiedPropertyName = function (token) { - switch (token.type) { - case 3 /* Identifier */: - case 8 /* StringLiteral */: - case 1 /* BooleanLiteral */: - case 5 /* NullLiteral */: - case 6 /* NumericLiteral */: - case 4 /* Keyword */: - return true; - case 7 /* Punctuator */: - return token.value === '['; - default: - break; - } - return false; - }; - Parser.prototype.parseGetterMethod = function () { - var node = this.createNode(); - var isGenerator = false; - var previousAllowYield = this.context.allowYield; - this.context.allowYield = false; - var formalParameters = this.parseFormalParameters(); - if (formalParameters.params.length > 0) { - this.tolerateError(messages_1.Messages.BadGetterArity); - } - var method = this.parsePropertyMethod(formalParameters); - this.context.allowYield = previousAllowYield; - return this.finalize(node, new Node.FunctionExpression(null, formalParameters.params, method, isGenerator)); - }; - Parser.prototype.parseSetterMethod = function () { - var node = this.createNode(); - var isGenerator = false; - var previousAllowYield = this.context.allowYield; - this.context.allowYield = false; - var formalParameters = this.parseFormalParameters(); - if (formalParameters.params.length !== 1) { - this.tolerateError(messages_1.Messages.BadSetterArity); - } - else if (formalParameters.params[0] instanceof Node.RestElement) { - this.tolerateError(messages_1.Messages.BadSetterRestParameter); - } - var method = this.parsePropertyMethod(formalParameters); - this.context.allowYield = previousAllowYield; - return this.finalize(node, new Node.FunctionExpression(null, formalParameters.params, method, isGenerator)); - }; - Parser.prototype.parseGeneratorMethod = function () { - var node = this.createNode(); - var isGenerator = true; - var previousAllowYield = this.context.allowYield; - this.context.allowYield = true; - var params = this.parseFormalParameters(); - this.context.allowYield = false; - var method = this.parsePropertyMethod(params); - this.context.allowYield = previousAllowYield; - return this.finalize(node, new Node.FunctionExpression(null, params.params, method, isGenerator)); - }; - // https://tc39.github.io/ecma262/#sec-generator-function-definitions - Parser.prototype.isStartOfExpression = function () { - var start = true; - var value = this.lookahead.value; - switch (this.lookahead.type) { - case 7 /* Punctuator */: - start = (value === '[') || (value === '(') || (value === '{') || - (value === '+') || (value === '-') || - (value === '!') || (value === '~') || - (value === '++') || (value === '--') || - (value === '/') || (value === '/='); // regular expression literal - break; - case 4 /* Keyword */: - start = (value === 'class') || (value === 'delete') || - (value === 'function') || (value === 'let') || (value === 'new') || - (value === 'super') || (value === 'this') || (value === 'typeof') || - (value === 'void') || (value === 'yield'); - break; - default: - break; - } - return start; - }; - Parser.prototype.parseYieldExpression = function () { - var node = this.createNode(); - this.expectKeyword('yield'); - var argument = null; - var delegate = false; - if (!this.hasLineTerminator) { - var previousAllowYield = this.context.allowYield; - this.context.allowYield = false; - delegate = this.match('*'); - if (delegate) { - this.nextToken(); - argument = this.parseAssignmentExpression(); - } - else if (this.isStartOfExpression()) { - argument = this.parseAssignmentExpression(); - } - this.context.allowYield = previousAllowYield; - } - return this.finalize(node, new Node.YieldExpression(argument, delegate)); - }; - // https://tc39.github.io/ecma262/#sec-class-definitions - Parser.prototype.parseClassElement = function (hasConstructor) { - var token = this.lookahead; - var node = this.createNode(); - var kind = ''; - var key = null; - var value = null; - var computed = false; - var method = false; - var isStatic = false; - var isAsync = false; - if (this.match('*')) { - this.nextToken(); - } - else { - computed = this.match('['); - key = this.parseObjectPropertyKey(); - var id = key; - if (id.name === 'static' && (this.qualifiedPropertyName(this.lookahead) || this.match('*'))) { - token = this.lookahead; - isStatic = true; - computed = this.match('['); - if (this.match('*')) { - this.nextToken(); - } - else { - key = this.parseObjectPropertyKey(); - } - } - if ((token.type === 3 /* Identifier */) && !this.hasLineTerminator && (token.value === 'async')) { - var punctuator = this.lookahead.value; - if (punctuator !== ':' && punctuator !== '(' && punctuator !== '*') { - isAsync = true; - token = this.lookahead; - key = this.parseObjectPropertyKey(); - if (token.type === 3 /* Identifier */) { - if (token.value === 'get' || token.value === 'set') { - this.tolerateUnexpectedToken(token); - } - else if (token.value === 'constructor') { - this.tolerateUnexpectedToken(token, messages_1.Messages.ConstructorIsAsync); - } - } - } - } - } - var lookaheadPropertyKey = this.qualifiedPropertyName(this.lookahead); - if (token.type === 3 /* Identifier */) { - if (token.value === 'get' && lookaheadPropertyKey) { - kind = 'get'; - computed = this.match('['); - key = this.parseObjectPropertyKey(); - this.context.allowYield = false; - value = this.parseGetterMethod(); - } - else if (token.value === 'set' && lookaheadPropertyKey) { - kind = 'set'; - computed = this.match('['); - key = this.parseObjectPropertyKey(); - value = this.parseSetterMethod(); - } - } - else if (token.type === 7 /* Punctuator */ && token.value === '*' && lookaheadPropertyKey) { - kind = 'init'; - computed = this.match('['); - key = this.parseObjectPropertyKey(); - value = this.parseGeneratorMethod(); - method = true; - } - if (!kind && key && this.match('(')) { - kind = 'init'; - value = isAsync ? this.parsePropertyMethodAsyncFunction() : this.parsePropertyMethodFunction(); - method = true; - } - if (!kind) { - this.throwUnexpectedToken(this.lookahead); - } - if (kind === 'init') { - kind = 'method'; - } - if (!computed) { - if (isStatic && this.isPropertyKey(key, 'prototype')) { - this.throwUnexpectedToken(token, messages_1.Messages.StaticPrototype); - } - if (!isStatic && this.isPropertyKey(key, 'constructor')) { - if (kind !== 'method' || !method || (value && value.generator)) { - this.throwUnexpectedToken(token, messages_1.Messages.ConstructorSpecialMethod); - } - if (hasConstructor.value) { - this.throwUnexpectedToken(token, messages_1.Messages.DuplicateConstructor); - } - else { - hasConstructor.value = true; - } - kind = 'constructor'; - } - } - return this.finalize(node, new Node.MethodDefinition(key, computed, value, kind, isStatic)); - }; - Parser.prototype.parseClassElementList = function () { - var body = []; - var hasConstructor = { value: false }; - this.expect('{'); - while (!this.match('}')) { - if (this.match(';')) { - this.nextToken(); - } - else { - body.push(this.parseClassElement(hasConstructor)); - } - } - this.expect('}'); - return body; - }; - Parser.prototype.parseClassBody = function () { - var node = this.createNode(); - var elementList = this.parseClassElementList(); - return this.finalize(node, new Node.ClassBody(elementList)); - }; - Parser.prototype.parseClassDeclaration = function (identifierIsOptional) { - var node = this.createNode(); - var previousStrict = this.context.strict; - this.context.strict = true; - this.expectKeyword('class'); - var id = (identifierIsOptional && (this.lookahead.type !== 3 /* Identifier */)) ? null : this.parseVariableIdentifier(); - var superClass = null; - if (this.matchKeyword('extends')) { - this.nextToken(); - superClass = this.isolateCoverGrammar(this.parseLeftHandSideExpressionAllowCall); - } - var classBody = this.parseClassBody(); - this.context.strict = previousStrict; - return this.finalize(node, new Node.ClassDeclaration(id, superClass, classBody)); - }; - Parser.prototype.parseClassExpression = function () { - var node = this.createNode(); - var previousStrict = this.context.strict; - this.context.strict = true; - this.expectKeyword('class'); - var id = (this.lookahead.type === 3 /* Identifier */) ? this.parseVariableIdentifier() : null; - var superClass = null; - if (this.matchKeyword('extends')) { - this.nextToken(); - superClass = this.isolateCoverGrammar(this.parseLeftHandSideExpressionAllowCall); - } - var classBody = this.parseClassBody(); - this.context.strict = previousStrict; - return this.finalize(node, new Node.ClassExpression(id, superClass, classBody)); - }; - // https://tc39.github.io/ecma262/#sec-scripts - // https://tc39.github.io/ecma262/#sec-modules - Parser.prototype.parseModule = function () { - this.context.strict = true; - this.context.isModule = true; - var node = this.createNode(); - var body = this.parseDirectivePrologues(); - while (this.lookahead.type !== 2 /* EOF */) { - body.push(this.parseStatementListItem()); - } - return this.finalize(node, new Node.Module(body)); - }; - Parser.prototype.parseScript = function () { - var node = this.createNode(); - var body = this.parseDirectivePrologues(); - while (this.lookahead.type !== 2 /* EOF */) { - body.push(this.parseStatementListItem()); - } - return this.finalize(node, new Node.Script(body)); - }; - // https://tc39.github.io/ecma262/#sec-imports - Parser.prototype.parseModuleSpecifier = function () { - var node = this.createNode(); - if (this.lookahead.type !== 8 /* StringLiteral */) { - this.throwError(messages_1.Messages.InvalidModuleSpecifier); - } - var token = this.nextToken(); - var raw = this.getTokenRaw(token); - return this.finalize(node, new Node.Literal(token.value, raw)); - }; - // import {} ...; - Parser.prototype.parseImportSpecifier = function () { - var node = this.createNode(); - var imported; - var local; - if (this.lookahead.type === 3 /* Identifier */) { - imported = this.parseVariableIdentifier(); - local = imported; - if (this.matchContextualKeyword('as')) { - this.nextToken(); - local = this.parseVariableIdentifier(); - } - } - else { - imported = this.parseIdentifierName(); - local = imported; - if (this.matchContextualKeyword('as')) { - this.nextToken(); - local = this.parseVariableIdentifier(); - } - else { - this.throwUnexpectedToken(this.nextToken()); - } - } - return this.finalize(node, new Node.ImportSpecifier(local, imported)); - }; - // {foo, bar as bas} - Parser.prototype.parseNamedImports = function () { - this.expect('{'); - var specifiers = []; - while (!this.match('}')) { - specifiers.push(this.parseImportSpecifier()); - if (!this.match('}')) { - this.expect(','); - } - } - this.expect('}'); - return specifiers; - }; - // import ...; - Parser.prototype.parseImportDefaultSpecifier = function () { - var node = this.createNode(); - var local = this.parseIdentifierName(); - return this.finalize(node, new Node.ImportDefaultSpecifier(local)); - }; - // import <* as foo> ...; - Parser.prototype.parseImportNamespaceSpecifier = function () { - var node = this.createNode(); - this.expect('*'); - if (!this.matchContextualKeyword('as')) { - this.throwError(messages_1.Messages.NoAsAfterImportNamespace); - } - this.nextToken(); - var local = this.parseIdentifierName(); - return this.finalize(node, new Node.ImportNamespaceSpecifier(local)); - }; - Parser.prototype.parseImportDeclaration = function () { - if (this.context.inFunctionBody) { - this.throwError(messages_1.Messages.IllegalImportDeclaration); - } - var node = this.createNode(); - this.expectKeyword('import'); - var src; - var specifiers = []; - if (this.lookahead.type === 8 /* StringLiteral */) { - // import 'foo'; - src = this.parseModuleSpecifier(); - } - else { - if (this.match('{')) { - // import {bar} - specifiers = specifiers.concat(this.parseNamedImports()); - } - else if (this.match('*')) { - // import * as foo - specifiers.push(this.parseImportNamespaceSpecifier()); - } - else if (this.isIdentifierName(this.lookahead) && !this.matchKeyword('default')) { - // import foo - specifiers.push(this.parseImportDefaultSpecifier()); - if (this.match(',')) { - this.nextToken(); - if (this.match('*')) { - // import foo, * as foo - specifiers.push(this.parseImportNamespaceSpecifier()); - } - else if (this.match('{')) { - // import foo, {bar} - specifiers = specifiers.concat(this.parseNamedImports()); - } - else { - this.throwUnexpectedToken(this.lookahead); - } - } - } - else { - this.throwUnexpectedToken(this.nextToken()); - } - if (!this.matchContextualKeyword('from')) { - var message = this.lookahead.value ? messages_1.Messages.UnexpectedToken : messages_1.Messages.MissingFromClause; - this.throwError(message, this.lookahead.value); - } - this.nextToken(); - src = this.parseModuleSpecifier(); - } - this.consumeSemicolon(); - return this.finalize(node, new Node.ImportDeclaration(specifiers, src)); - }; - // https://tc39.github.io/ecma262/#sec-exports - Parser.prototype.parseExportSpecifier = function () { - var node = this.createNode(); - var local = this.parseIdentifierName(); - var exported = local; - if (this.matchContextualKeyword('as')) { - this.nextToken(); - exported = this.parseIdentifierName(); - } - return this.finalize(node, new Node.ExportSpecifier(local, exported)); - }; - Parser.prototype.parseExportDeclaration = function () { - if (this.context.inFunctionBody) { - this.throwError(messages_1.Messages.IllegalExportDeclaration); - } - var node = this.createNode(); - this.expectKeyword('export'); - var exportDeclaration; - if (this.matchKeyword('default')) { - // export default ... - this.nextToken(); - if (this.matchKeyword('function')) { - // export default function foo () {} - // export default function () {} - var declaration = this.parseFunctionDeclaration(true); - exportDeclaration = this.finalize(node, new Node.ExportDefaultDeclaration(declaration)); - } - else if (this.matchKeyword('class')) { - // export default class foo {} - var declaration = this.parseClassDeclaration(true); - exportDeclaration = this.finalize(node, new Node.ExportDefaultDeclaration(declaration)); - } - else if (this.matchContextualKeyword('async')) { - // export default async function f () {} - // export default async function () {} - // export default async x => x - var declaration = this.matchAsyncFunction() ? this.parseFunctionDeclaration(true) : this.parseAssignmentExpression(); - exportDeclaration = this.finalize(node, new Node.ExportDefaultDeclaration(declaration)); - } - else { - if (this.matchContextualKeyword('from')) { - this.throwError(messages_1.Messages.UnexpectedToken, this.lookahead.value); - } - // export default {}; - // export default []; - // export default (1 + 2); - var declaration = this.match('{') ? this.parseObjectInitializer() : - this.match('[') ? this.parseArrayInitializer() : this.parseAssignmentExpression(); - this.consumeSemicolon(); - exportDeclaration = this.finalize(node, new Node.ExportDefaultDeclaration(declaration)); - } - } - else if (this.match('*')) { - // export * from 'foo'; - this.nextToken(); - if (!this.matchContextualKeyword('from')) { - var message = this.lookahead.value ? messages_1.Messages.UnexpectedToken : messages_1.Messages.MissingFromClause; - this.throwError(message, this.lookahead.value); - } - this.nextToken(); - var src = this.parseModuleSpecifier(); - this.consumeSemicolon(); - exportDeclaration = this.finalize(node, new Node.ExportAllDeclaration(src)); - } - else if (this.lookahead.type === 4 /* Keyword */) { - // export var f = 1; - var declaration = void 0; - switch (this.lookahead.value) { - case 'let': - case 'const': - declaration = this.parseLexicalDeclaration({ inFor: false }); - break; - case 'var': - case 'class': - case 'function': - declaration = this.parseStatementListItem(); - break; - default: - this.throwUnexpectedToken(this.lookahead); - } - exportDeclaration = this.finalize(node, new Node.ExportNamedDeclaration(declaration, [], null)); - } - else if (this.matchAsyncFunction()) { - var declaration = this.parseFunctionDeclaration(); - exportDeclaration = this.finalize(node, new Node.ExportNamedDeclaration(declaration, [], null)); - } - else { - var specifiers = []; - var source = null; - var isExportFromIdentifier = false; - this.expect('{'); - while (!this.match('}')) { - isExportFromIdentifier = isExportFromIdentifier || this.matchKeyword('default'); - specifiers.push(this.parseExportSpecifier()); - if (!this.match('}')) { - this.expect(','); - } - } - this.expect('}'); - if (this.matchContextualKeyword('from')) { - // export {default} from 'foo'; - // export {foo} from 'foo'; - this.nextToken(); - source = this.parseModuleSpecifier(); - this.consumeSemicolon(); - } - else if (isExportFromIdentifier) { - // export {default}; // missing fromClause - var message = this.lookahead.value ? messages_1.Messages.UnexpectedToken : messages_1.Messages.MissingFromClause; - this.throwError(message, this.lookahead.value); - } - else { - // export {foo}; - this.consumeSemicolon(); - } - exportDeclaration = this.finalize(node, new Node.ExportNamedDeclaration(null, specifiers, source)); - } - return exportDeclaration; - }; - return Parser; - }()); - exports.Parser = Parser; - - -/***/ }, -/* 9 */ -/***/ function(module, exports) { - - "use strict"; - // Ensure the condition is true, otherwise throw an error. - // This is only to have a better contract semantic, i.e. another safety net - // to catch a logic error. The condition shall be fulfilled in normal case. - // Do NOT use this to enforce a certain condition on any user input. - Object.defineProperty(exports, "__esModule", { value: true }); - function assert(condition, message) { - /* istanbul ignore if */ - if (!condition) { - throw new Error('ASSERT: ' + message); - } - } - exports.assert = assert; - - -/***/ }, -/* 10 */ -/***/ function(module, exports) { - - "use strict"; - /* tslint:disable:max-classes-per-file */ - Object.defineProperty(exports, "__esModule", { value: true }); - var ErrorHandler = (function () { - function ErrorHandler() { - this.errors = []; - this.tolerant = false; - } - ErrorHandler.prototype.recordError = function (error) { - this.errors.push(error); - }; - ErrorHandler.prototype.tolerate = function (error) { - if (this.tolerant) { - this.recordError(error); - } - else { - throw error; - } - }; - ErrorHandler.prototype.constructError = function (msg, column) { - var error = new Error(msg); - try { - throw error; - } - catch (base) { - /* istanbul ignore else */ - if (Object.create && Object.defineProperty) { - error = Object.create(base); - Object.defineProperty(error, 'column', { value: column }); - } - } - /* istanbul ignore next */ - return error; - }; - ErrorHandler.prototype.createError = function (index, line, col, description) { - var msg = 'Line ' + line + ': ' + description; - var error = this.constructError(msg, col); - error.index = index; - error.lineNumber = line; - error.description = description; - return error; - }; - ErrorHandler.prototype.throwError = function (index, line, col, description) { - throw this.createError(index, line, col, description); - }; - ErrorHandler.prototype.tolerateError = function (index, line, col, description) { - var error = this.createError(index, line, col, description); - if (this.tolerant) { - this.recordError(error); - } - else { - throw error; - } - }; - return ErrorHandler; - }()); - exports.ErrorHandler = ErrorHandler; - - -/***/ }, -/* 11 */ -/***/ function(module, exports) { - - "use strict"; - Object.defineProperty(exports, "__esModule", { value: true }); - // Error messages should be identical to V8. - exports.Messages = { - BadGetterArity: 'Getter must not have any formal parameters', - BadSetterArity: 'Setter must have exactly one formal parameter', - BadSetterRestParameter: 'Setter function argument must not be a rest parameter', - ConstructorIsAsync: 'Class constructor may not be an async method', - ConstructorSpecialMethod: 'Class constructor may not be an accessor', - DeclarationMissingInitializer: 'Missing initializer in %0 declaration', - DefaultRestParameter: 'Unexpected token =', - DuplicateBinding: 'Duplicate binding %0', - DuplicateConstructor: 'A class may only have one constructor', - DuplicateProtoProperty: 'Duplicate __proto__ fields are not allowed in object literals', - ForInOfLoopInitializer: '%0 loop variable declaration may not have an initializer', - GeneratorInLegacyContext: 'Generator declarations are not allowed in legacy contexts', - IllegalBreak: 'Illegal break statement', - IllegalContinue: 'Illegal continue statement', - IllegalExportDeclaration: 'Unexpected token', - IllegalImportDeclaration: 'Unexpected token', - IllegalLanguageModeDirective: 'Illegal \'use strict\' directive in function with non-simple parameter list', - IllegalReturn: 'Illegal return statement', - InvalidEscapedReservedWord: 'Keyword must not contain escaped characters', - InvalidHexEscapeSequence: 'Invalid hexadecimal escape sequence', - InvalidLHSInAssignment: 'Invalid left-hand side in assignment', - InvalidLHSInForIn: 'Invalid left-hand side in for-in', - InvalidLHSInForLoop: 'Invalid left-hand side in for-loop', - InvalidModuleSpecifier: 'Unexpected token', - InvalidRegExp: 'Invalid regular expression', - LetInLexicalBinding: 'let is disallowed as a lexically bound name', - MissingFromClause: 'Unexpected token', - MultipleDefaultsInSwitch: 'More than one default clause in switch statement', - NewlineAfterThrow: 'Illegal newline after throw', - NoAsAfterImportNamespace: 'Unexpected token', - NoCatchOrFinally: 'Missing catch or finally after try', - ParameterAfterRestParameter: 'Rest parameter must be last formal parameter', - Redeclaration: '%0 \'%1\' has already been declared', - StaticPrototype: 'Classes may not have static property named prototype', - StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode', - StrictDelete: 'Delete of an unqualified identifier in strict mode.', - StrictFunction: 'In strict mode code, functions can only be declared at top level or inside a block', - StrictFunctionName: 'Function name may not be eval or arguments in strict mode', - StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode', - StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode', - StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode', - StrictModeWith: 'Strict mode code may not include a with statement', - StrictOctalLiteral: 'Octal literals are not allowed in strict mode.', - StrictParamDupe: 'Strict mode function may not have duplicate parameter names', - StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode', - StrictReservedWord: 'Use of future reserved word in strict mode', - StrictVarName: 'Variable name may not be eval or arguments in strict mode', - TemplateOctalLiteral: 'Octal literals are not allowed in template strings.', - UnexpectedEOS: 'Unexpected end of input', - UnexpectedIdentifier: 'Unexpected identifier', - UnexpectedNumber: 'Unexpected number', - UnexpectedReserved: 'Unexpected reserved word', - UnexpectedString: 'Unexpected string', - UnexpectedTemplate: 'Unexpected quasi %0', - UnexpectedToken: 'Unexpected token %0', - UnexpectedTokenIllegal: 'Unexpected token ILLEGAL', - UnknownLabel: 'Undefined label \'%0\'', - UnterminatedRegExp: 'Invalid regular expression: missing /' - }; - - -/***/ }, -/* 12 */ -/***/ function(module, exports, __webpack_require__) { - - "use strict"; - Object.defineProperty(exports, "__esModule", { value: true }); - var assert_1 = __webpack_require__(9); - var character_1 = __webpack_require__(4); - var messages_1 = __webpack_require__(11); - function hexValue(ch) { - return '0123456789abcdef'.indexOf(ch.toLowerCase()); - } - function octalValue(ch) { - return '01234567'.indexOf(ch); - } - var Scanner = (function () { - function Scanner(code, handler) { - this.source = code; - this.errorHandler = handler; - this.trackComment = false; - this.length = code.length; - this.index = 0; - this.lineNumber = (code.length > 0) ? 1 : 0; - this.lineStart = 0; - this.curlyStack = []; - } - Scanner.prototype.saveState = function () { - return { - index: this.index, - lineNumber: this.lineNumber, - lineStart: this.lineStart - }; - }; - Scanner.prototype.restoreState = function (state) { - this.index = state.index; - this.lineNumber = state.lineNumber; - this.lineStart = state.lineStart; - }; - Scanner.prototype.eof = function () { - return this.index >= this.length; - }; - Scanner.prototype.throwUnexpectedToken = function (message) { - if (message === void 0) { message = messages_1.Messages.UnexpectedTokenIllegal; } - return this.errorHandler.throwError(this.index, this.lineNumber, this.index - this.lineStart + 1, message); - }; - Scanner.prototype.tolerateUnexpectedToken = function (message) { - if (message === void 0) { message = messages_1.Messages.UnexpectedTokenIllegal; } - this.errorHandler.tolerateError(this.index, this.lineNumber, this.index - this.lineStart + 1, message); - }; - // https://tc39.github.io/ecma262/#sec-comments - Scanner.prototype.skipSingleLineComment = function (offset) { - var comments = []; - var start, loc; - if (this.trackComment) { - comments = []; - start = this.index - offset; - loc = { - start: { - line: this.lineNumber, - column: this.index - this.lineStart - offset - }, - end: {} - }; - } - while (!this.eof()) { - var ch = this.source.charCodeAt(this.index); - ++this.index; - if (character_1.Character.isLineTerminator(ch)) { - if (this.trackComment) { - loc.end = { - line: this.lineNumber, - column: this.index - this.lineStart - 1 - }; - var entry = { - multiLine: false, - slice: [start + offset, this.index - 1], - range: [start, this.index - 1], - loc: loc - }; - comments.push(entry); - } - if (ch === 13 && this.source.charCodeAt(this.index) === 10) { - ++this.index; - } - ++this.lineNumber; - this.lineStart = this.index; - return comments; - } - } - if (this.trackComment) { - loc.end = { - line: this.lineNumber, - column: this.index - this.lineStart - }; - var entry = { - multiLine: false, - slice: [start + offset, this.index], - range: [start, this.index], - loc: loc - }; - comments.push(entry); - } - return comments; - }; - Scanner.prototype.skipMultiLineComment = function () { - var comments = []; - var start, loc; - if (this.trackComment) { - comments = []; - start = this.index - 2; - loc = { - start: { - line: this.lineNumber, - column: this.index - this.lineStart - 2 - }, - end: {} - }; - } - while (!this.eof()) { - var ch = this.source.charCodeAt(this.index); - if (character_1.Character.isLineTerminator(ch)) { - if (ch === 0x0D && this.source.charCodeAt(this.index + 1) === 0x0A) { - ++this.index; - } - ++this.lineNumber; - ++this.index; - this.lineStart = this.index; - } - else if (ch === 0x2A) { - // Block comment ends with '*/'. - if (this.source.charCodeAt(this.index + 1) === 0x2F) { - this.index += 2; - if (this.trackComment) { - loc.end = { - line: this.lineNumber, - column: this.index - this.lineStart - }; - var entry = { - multiLine: true, - slice: [start + 2, this.index - 2], - range: [start, this.index], - loc: loc - }; - comments.push(entry); - } - return comments; - } - ++this.index; - } - else { - ++this.index; - } - } - // Ran off the end of the file - the whole thing is a comment - if (this.trackComment) { - loc.end = { - line: this.lineNumber, - column: this.index - this.lineStart - }; - var entry = { - multiLine: true, - slice: [start + 2, this.index], - range: [start, this.index], - loc: loc - }; - comments.push(entry); - } - this.tolerateUnexpectedToken(); - return comments; - }; - Scanner.prototype.scanComments = function () { - var comments; - if (this.trackComment) { - comments = []; - } - var start = (this.index === 0); - while (!this.eof()) { - var ch = this.source.charCodeAt(this.index); - if (character_1.Character.isWhiteSpace(ch)) { - ++this.index; - } - else if (character_1.Character.isLineTerminator(ch)) { - ++this.index; - if (ch === 0x0D && this.source.charCodeAt(this.index) === 0x0A) { - ++this.index; - } - ++this.lineNumber; - this.lineStart = this.index; - start = true; - } - else if (ch === 0x2F) { - ch = this.source.charCodeAt(this.index + 1); - if (ch === 0x2F) { - this.index += 2; - var comment = this.skipSingleLineComment(2); - if (this.trackComment) { - comments = comments.concat(comment); - } - start = true; - } - else if (ch === 0x2A) { - this.index += 2; - var comment = this.skipMultiLineComment(); - if (this.trackComment) { - comments = comments.concat(comment); - } - } - else { - break; - } - } - else if (start && ch === 0x2D) { - // U+003E is '>' - if ((this.source.charCodeAt(this.index + 1) === 0x2D) && (this.source.charCodeAt(this.index + 2) === 0x3E)) { - // '-->' is a single-line comment - this.index += 3; - var comment = this.skipSingleLineComment(3); - if (this.trackComment) { - comments = comments.concat(comment); - } - } - else { - break; - } - } - else if (ch === 0x3C) { - if (this.source.slice(this.index + 1, this.index + 4) === '!--') { - this.index += 4; // `