diff --git a/.github/workflows/browser-tests.yml b/.github/workflows/browser-tests.yml index b982603d..ad14e224 100644 --- a/.github/workflows/browser-tests.yml +++ b/.github/workflows/browser-tests.yml @@ -4,7 +4,7 @@ on: pull_request: push: branches: - - main + - 3.x-stable env: NODE_VERSION: 22.x diff --git a/.github/workflows/browserstack-git.yml b/.github/workflows/browserstack-git.yml deleted file mode 100644 index 0a3d2d0c..00000000 --- a/.github/workflows/browserstack-git.yml +++ /dev/null @@ -1,68 +0,0 @@ -name: Browserstack (Core git) - -on: - push: - branches: - - main - # Once a week every Tuesday - schedule: - - cron: "42 1 * * 2" - -jobs: - test: - runs-on: ubuntu-latest - environment: browserstack - env: - BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }} - BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }} - NODE_VERSION: 22.x - name: ${{ matrix.BROWSER }} - concurrency: - group: ${{ matrix.BROWSER }} - ${{ github.sha }} - timeout-minutes: 30 - strategy: - fail-fast: false - matrix: - BROWSER: - - 'IE_11' - - 'Safari_latest' - - 'Safari_latest-1' - - 'Chrome_latest' - - 'Chrome_latest-1' - - 'Opera_latest' - - 'Edge_latest' - - 'Edge_latest-1' - - 'Firefox_latest' - - 'Firefox_latest-1' - - 'Firefox_115' - - '__iOS_18' - - '__iOS_17' - - '__iOS_16' - steps: - - name: Checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 - with: - node-version: ${{ env.NODE_VERSION }} - - - name: Cache - uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 - with: - path: ~/.npm - key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock- - - - name: Install dependencies - run: npm install - - - name: Pretest script - run: npm run pretest - - - name: Test - run: | - npm run test:unit -- -v -c jtr-git.yml \ - --browserstack "${{ matrix.BROWSER }}" \ - --run-id ${{ github.run_id }} \ diff --git a/.github/workflows/browserstack-3.x.yml b/.github/workflows/browserstack.yml similarity index 78% rename from .github/workflows/browserstack-3.x.yml rename to .github/workflows/browserstack.yml index fd62a28e..594197f7 100644 --- a/.github/workflows/browserstack-3.x.yml +++ b/.github/workflows/browserstack.yml @@ -1,9 +1,9 @@ -name: Browserstack (Core 3.x) +name: Browserstack on: push: branches: - - main + - 3.x-stable # Once a week every Tuesday schedule: - cron: "12 2 * * 2" @@ -51,9 +51,19 @@ jobs: - '__iOS_13' - '__iOS_12' - '__iOS_11' - - '__iOS_10' + + # iOS 10 is a tier 4 device as of January 2025 and its availability + # is poor, leading to frequent test timeouts. Skip testing on it. + # See https://www.browserstack.com/device-tiers + # - '__iOS_10' + + # Versions below are not officially supported by BrowserStack as + # they use emulators instead of real devices. We include them as + # long as they still work. - '__iOS_9' - '__iOS_8' + # iOS 7 emulators no longer work properly + # - '__iOS_7' steps: - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 @@ -79,6 +89,6 @@ jobs: - name: Test run: | - npm run test:unit -- -v -c jtr-3.x.yml \ + npm run test:unit -- -v -c jtr-ci.yml \ --browserstack "${{ matrix.BROWSER }}" \ --run-id ${{ github.run_id }} \ diff --git a/.github/workflows/filestash.yml b/.github/workflows/filestash.yml index 1bd552f0..34ca105d 100644 --- a/.github/workflows/filestash.yml +++ b/.github/workflows/filestash.yml @@ -3,7 +3,7 @@ name: Filestash on: push: branches: - - main + - 3.x-stable permissions: contents: read # to fetch code (actions/checkout) @@ -47,5 +47,5 @@ jobs: - name: Upload to Filestash run: | - rsync dist/jquery-migrate.js filestash@"${{ secrets.FILESTASH_SERVER }}":jquery-migrate-git.js - rsync dist/jquery-migrate.min.js filestash@"${{ secrets.FILESTASH_SERVER }}":jquery-migrate-git.min.js + rsync dist/jquery-migrate.js filestash@"${{ secrets.FILESTASH_SERVER }}":jquery-migrate-3.x-git.js + rsync dist/jquery-migrate.min.js filestash@"${{ secrets.FILESTASH_SERVER }}":jquery-migrate-3.x-git.min.js diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cb18176c..dd91e121 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -47,7 +47,7 @@ Make sure you have reproduced the bug with all browser extensions and add-ons di ### Try the latest version of jQuery Migrate -Bugs in old versions of jQuery Migrate may have already been fixed. In order to avoid reporting known issues, make sure you are always testing against the [latest build](https://releases.jquery.com/git/jquery-migrate-git.js). We cannot fix bugs in older released files, if a bug has been fixed in a subsequent version of jQuery Migrate the site should upgrade. +Bugs in old versions of jQuery Migrate may have already been fixed. In order to avoid reporting known issues, make sure you are always testing against the [latest build](https://releases.jquery.com/git/jquery-migrate-3.x-git.js). We cannot fix bugs in older released files, if a bug has been fixed in a subsequent version of jQuery Migrate the site should upgrade. ### Simplify the test case @@ -78,16 +78,16 @@ Change directory to the newly created dir `jquery-migrate/`: $ cd jquery-migrate ``` -Add the jQuery Migrate `main` as a remote (e.g. `upstream`): +Add the jQuery Migrate `3.x-stable` as a remote (e.g. `upstream`): ```bash $ git remote add upstream git@github.com:jquery/jquery-migrate.git ``` -Get in the habit of pulling in the "upstream" main to stay up to date as jQuery Migrate receives new commits: +Get in the habit of pulling in the "upstream" `3.x-stable` to stay up to date as jQuery Migrate receives new commits: ```bash -$ git pull upstream main +$ git pull upstream 3.x-stable ``` Install the necessary dependencies: diff --git a/README.md b/README.md index 5512c8e4..3eb27665 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![CI Status](https://github.com/jquery/jquery-migrate/actions/workflows/node.js.yml/badge.svg?branch=main) +![CI Status](https://github.com/jquery/jquery-migrate/actions/workflows/node.js.yml/badge.svg?branch=3.x-stable) #### NOTE: To upgrade to jQuery 3.0, you first need version 1.12.x or 2.2.x. If you're using an older version, first upgrade to one of these versions using [jQuery Migrate 1.x](https://github.com/jquery/jquery-migrate/tree/1.x-stable#readme), to resolve any compatibility issues. For more information about the changes made in jQuery 3.0, see the [upgrade guide](https://jquery.com/upgrade-guide/3.0/) and [blog post](https://blog.jquery.com/2016/06/09/jquery-3-0-final-released/). @@ -11,14 +11,14 @@ That way you can spot and fix what otherwise would have been errors, until you n The following table indicates which jQuery Migrate versions can be used with which jQuery versions: -| jQuery version | jQuery Migrate version | -|----------------|-------------------------| -| 1.x | 1.x | -| 2.x | 1.x | -| 3.x | 3.x / 4.x[1] | -| 4.x | 3.x / 4.x[1] | +| jQuery version | jQuery Migrate version | +|----------------|------------------------| +| 1.x | 1.x | +| 2.x | 1.x | +| 3.x | 3.x | +| 4.x | 4.x | -[1] NOTE: jQuery Migrate 4.x only supports the same browser as jQuery 4.x does. If you need to support Edge Legacy, Internet Explorer 9-10 or iOS 7+ (and not just 3 latest versions), use jQuery Migrate 3.x. +Each jQuery Migrate version supports the same browsers that the jQuery version used with it. ## Usage @@ -40,7 +40,7 @@ The production build is minified and does not generate console warnings. It will | Debugging enabled |
✓
| | | Minified | |✓
| | Latest release (*may be hotlinked if desired*) | [jquery-migrate-3.5.2.js](https://code.jquery.com/jquery-migrate-3.5.2.js) | [jquery-migrate-3.5.2.min.js](https://code.jquery.com/jquery-migrate-3.5.2.min.js) | -| \* Latest work-in-progress build | [jquery-migrate-git.js](https://releases.jquery.com/git/jquery-migrate-git.js) | [jquery-migrate-git.min.js](https://releases.jquery.com/git/jquery-migrate-git.min.js) | +| \* Latest work-in-progress build | [jquery-migrate-3.x-git.js](https://releases.jquery.com/git/jquery-migrate-3.x-git.js) | [jquery-migrate-3.x-git.min.js](https://releases.jquery.com/git/jquery-migrate-3.x-git.min.js) | \* **Work-in-progress build:** Although this file represents the most recent updates to the plugin, it may not have been thoroughly tested. We do not recommend using this file on production sites since it may be unstable; use the released production version instead. @@ -50,7 +50,7 @@ The production build is minified and does not generate console warnings. It will The development version of the plugin displays warnings in the browser console. Older browsers such as IE9 doesn't support the console interface. No messages will be generated unless you include a debugging library such as [Firebug Lite](https://getfirebug.com/firebuglite) before including the jQuery Migrate plugin. Developers can also inspect the `jQuery.migrateWarnings` array to see what error messages have been generated. -All warnings generated by this plugin start with the string "JQMIGRATE". A list of the warnings you may see are in [warnings.md](https://github.com/jquery/jquery-migrate/blob/main/warnings.md). +All warnings generated by this plugin start with the string "JQMIGRATE". A list of the warnings you may see are in [warnings.md](https://github.com/jquery/jquery-migrate/blob/3.x-stable/warnings.md). ## Migrate Plugin API @@ -69,7 +69,7 @@ This plugin adds some properties to the `jQuery` object that can be used to prog `jQuery.migrateDeduplicateWarnings`: By default, Migrate only gives a specific warning once. If you set this property to `false` it will give a warning for every occurrence each time it happens. Note that this can generate a lot of output, for example when a warning occurs in a loop. -`jQuery.migrateDisablePatches`: Disables patches by their codes. You can find a code for each patch in square brackets in [warnings.md](https://github.com/jquery/jquery-migrate/blob/main/warnings.md). A limited number of warnings doesn't have codes defined and cannot be disabled. These are mostly setup issues like using an incorrect version of jQuery or loading Migrate multiple times. +`jQuery.migrateDisablePatches`: Disables patches by their codes. You can find a code for each patch in square brackets in [warnings.md](https://github.com/jquery/jquery-migrate/blob/3.x-stable/warnings.md). A limited number of warnings doesn't have codes defined and cannot be disabled. These are mostly setup issues like using an incorrect version of jQuery or loading Migrate multiple times. `jQuery.migrateDisablePatches`: Disables patches by their codes. diff --git a/build/release.js b/build/release.js index 92242abe..6dd74e05 100644 --- a/build/release.js +++ b/build/release.js @@ -22,7 +22,7 @@ var releaseVersion, prompt = enquirer.prompt, repoURL = "git@github.com:jquery/jquery-migrate.git", - branch = "main", + branch = "3.x-stable", // Windows needs the .cmd version but will find the non-.cmd // On Windows, also ensure the HOME environment variable is set @@ -211,7 +211,7 @@ async function publishToNPM( next ) { function setNextVersion( next ) { updateSourceVersion( nextVersion ); - updatePackageVersion( nextVersion, "main" ); + updatePackageVersion( nextVersion, "3.x-stable" ); git( [ "commit", "-a", "--no-verify", "-m", "Updating the source version to " + nextVersion ], next ); } @@ -281,7 +281,7 @@ function updateReadmeVersion() { } function setBlobVersion( s, v ) { - return s.replace( /\/blob\/(?:(\d+\.\d+[^\/]+)|main)/, "/blob/" + v ); + return s.replace( /\/blob\/(?:(\d+\.\d+[^\/]+)|3.x-stable)/, "/blob/" + v ); } function writeJsonSync( fname, json ) { diff --git a/jtr-3.x.yml b/jtr-ci.yml similarity index 100% rename from jtr-3.x.yml rename to jtr-ci.yml diff --git a/jtr-local.yml b/jtr-local.yml index fa5058e1..e0ab114b 100644 --- a/jtr-local.yml +++ b/jtr-local.yml @@ -2,10 +2,6 @@ version: 1 flags: jquery: - - git - - git.min - - git.slim - - git.slim.min - 3.x-git - 3.x-git.min - 3.x-git.slim @@ -18,6 +14,7 @@ flags: - 3.3.1 - 3.2.1 - 3.1.1 + - 3.1.1.slim - 3.0.0 retries: 1 diff --git a/package-lock.json b/package-lock.json index 96b7569f..32208064 100644 --- a/package-lock.json +++ b/package-lock.json @@ -879,10 +879,11 @@ "license": "MIT" }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", diff --git a/src/jquery/ajax.js b/src/jquery/ajax.js index 91555749..9c2bf679 100644 --- a/src/jquery/ajax.js +++ b/src/jquery/ajax.js @@ -1,4 +1,3 @@ -import { jQueryVersionSince } from "../compareVersions.js"; import { migrateWarn, migratePatchAndWarnFunc, migratePatchFunc } from "../main.js"; // Support jQuery slim which excludes the ajax module @@ -8,8 +7,7 @@ var oldAjax = jQuery.ajax, oldCallbacks = [], guid = "migrate-" + Date.now(), origJsonpCallback = jQuery.ajaxSettings.jsonpCallback, - rjsonp = /(=)\?(?=&|$)|\?\?/, - rquery = /\?/; + rjsonp = /(=)\?(?=&|$)|\?\?/; migratePatchFunc( jQuery, "ajax", function() { var jQXHR = oldAjax.apply( this, arguments ); @@ -45,120 +43,23 @@ jQuery.ajaxSetup( { // Register this prefilter before the jQuery one. Otherwise, a promoted // request is transformed into one with the script dataType, and we can't // catch it anymore. -if ( jQueryVersionSince( "4.0.0" ) ) { - - // Code mostly from: - // https://github.com/jquery/jquery/blob/fa0058af426c4e482059214c29c29f004254d9a1/src/ajax/jsonp.js#L20-L97 - jQuery.ajaxPrefilter( "+json", function( s, originalSettings, jqXHR ) { - - if ( !jQuery.migrateIsPatchEnabled( "jsonp-promotion" ) ) { - return; - } - - var callbackName, overwritten, responseContainer, - jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ? - "url" : - typeof s.data === "string" && - ( s.contentType || "" ) - .indexOf( "application/x-www-form-urlencoded" ) === 0 && - rjsonp.test( s.data ) && "data" - ); - - // Handle iff the expected data type is "jsonp" or we have a parameter to set - if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) { - migrateWarn( "jsonp-promotion", "JSON-to-JSONP auto-promotion is deprecated" ); - - // Get callback name, remembering preexisting value associated with it - callbackName = s.jsonpCallback = typeof s.jsonpCallback === "function" ? - s.jsonpCallback() : - s.jsonpCallback; - - // Insert callback into url or form data - if ( jsonProp ) { - s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName ); - } else if ( s.jsonp !== false ) { - s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; - } - - // Use data converter to retrieve json after script execution - s.converters[ "script json" ] = function() { - if ( !responseContainer ) { - jQuery.error( callbackName + " was not called" ); - } - return responseContainer[ 0 ]; - }; - - // Force json dataType - s.dataTypes[ 0 ] = "json"; - - // Install callback - overwritten = window[ callbackName ]; - window[ callbackName ] = function() { - responseContainer = arguments; - }; - - // Clean-up function (fires after converters) - jqXHR.always( function() { - - // If previous value didn't exist - remove it - if ( overwritten === undefined ) { - jQuery( window ).removeProp( callbackName ); - - // Otherwise restore preexisting value - } else { - window[ callbackName ] = overwritten; - } - - // Save back as free - if ( s[ callbackName ] ) { - - // Make sure that re-using the options doesn't screw things around - s.jsonpCallback = originalSettings.jsonpCallback; - - // Save the callback name for future use - oldCallbacks.push( callbackName ); - } - - // Call if it was a function and we have a response - if ( responseContainer && typeof overwritten === "function" ) { - overwritten( responseContainer[ 0 ] ); - } - - responseContainer = overwritten = undefined; - } ); - - // Delegate to script - return "script"; - } - } ); -} else { - - // jQuery <4 already contains this prefixer; don't duplicate the whole logic, - // but only enough to know when to warn. - jQuery.ajaxPrefilter( "+json", function( s ) { - - if ( !jQuery.migrateIsPatchEnabled( "jsonp-promotion" ) ) { - return; - } - - // Warn if JSON-to-JSONP auto-promotion happens. - if ( s.jsonp !== false && ( rjsonp.test( s.url ) || - typeof s.data === "string" && - ( s.contentType || "" ) - .indexOf( "application/x-www-form-urlencoded" ) === 0 && - rjsonp.test( s.data ) - ) ) { - migrateWarn( "jsonp-promotion", "JSON-to-JSONP auto-promotion is deprecated" ); - } - } ); -} +// jQuery <4 already contains this prefixer; don't duplicate the whole logic, +// but only enough to know when to warn. +jQuery.ajaxPrefilter( "+json", function( s ) { + if ( !jQuery.migrateIsPatchEnabled( "jsonp-promotion" ) ) { + return; + } -// Don't trigger the above logic in jQuery >=4 by default as the JSON-to-JSONP -// auto-promotion behavior is gone in jQuery 4.0 and as it has security implications, -// we don't want to restore the legacy behavior by default. -if ( jQueryVersionSince( "4.0.0" ) ) { - jQuery.migrateDisablePatches( "jsonp-promotion" ); -} + // Warn if JSON-to-JSONP auto-promotion happens. + if ( s.jsonp !== false && ( rjsonp.test( s.url ) || + typeof s.data === "string" && + ( s.contentType || "" ) + .indexOf( "application/x-www-form-urlencoded" ) === 0 && + rjsonp.test( s.data ) + ) ) { + migrateWarn( "jsonp-promotion", "JSON-to-JSONP auto-promotion is deprecated" ); + } +} ); } diff --git a/src/jquery/attributes.js b/src/jquery/attributes.js index f76b1499..be029948 100644 --- a/src/jquery/attributes.js +++ b/src/jquery/attributes.js @@ -1,5 +1,4 @@ import { migratePatchFunc, migrateWarn } from "../main.js"; -import { jQueryVersionSince } from "../compareVersions.js"; var oldRemoveAttr = jQuery.fn.removeAttr, oldJQueryAttr = jQuery.attr, @@ -36,15 +35,6 @@ jQuery.each( booleans.split( "|" ), function( _i, name ) { migrateWarn( "boolean-attributes", "Boolean attribute '" + name + "' value is different from its lowercased name" ); - - // jQuery <4 attr hooks setup is complex: there are attr - // hooks, bool hooks and selector attr handles. Only - // implement the logic in jQuery >=4 where it's missing - // and there are only attr hooks. - if ( jQueryVersionSince( "4.0.0" ) ) { - return name.toLowerCase(); - } - return null; } } @@ -72,12 +62,12 @@ jQuery.each( booleans.split( "|" ), function( _i, name ) { } return name; } - } else if ( !jQueryVersionSince( "4.0.0" ) ) { + } else { // jQuery <4 uses a private `boolHook` for the boolean attribute // setter. It's only activated if `attrHook` is not set, but we set - // it here in Migrate. Since we cannot access it, let's just repeat - // its contents here. + // it here in Migrate so jQuery would not use it. Since we cannot + // access it, let's just repeat its contents here. if ( value === false ) { // Remove boolean attributes when set to false diff --git a/src/jquery/core.js b/src/jquery/core.js index 7d92fefd..26d47a0f 100644 --- a/src/jquery/core.js +++ b/src/jquery/core.js @@ -1,24 +1,8 @@ import { jQueryVersionSince } from "../compareVersions.js"; -import { - migratePatchFunc, - migrateWarn, - migratePatchAndWarnFunc, - migrateWarnProp -} from "../main.js"; +import { migratePatchAndWarnFunc } from "../main.js"; import "../disablePatches.js"; -var findProp, - arr = [], - push = arr.push, - slice = arr.slice, - sort = arr.sort, - splice = arr.splice, - class2type = {}, - oldInit = jQuery.fn.init, - oldFind = jQuery.find, - - rattrHashTest = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/, - rattrHashGlob = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/g, +var class2type = {}, // Require that the "whitespace run" starts from a non-whitespace // to avoid O(N^2) behavior when the engine would try matching "\s+$" at each space position. @@ -37,68 +21,6 @@ function isFunction( obj ) { typeof obj.item !== "function"; } -migratePatchFunc( jQuery.fn, "init", function( arg1 ) { - var args = Array.prototype.slice.call( arguments ); - - if ( jQuery.migrateIsPatchEnabled( "selector-empty-id" ) && - typeof arg1 === "string" && arg1 === "#" ) { - - // JQuery( "#" ) is a bogus ID selector, but it returned an empty set - // before jQuery 3.0 - migrateWarn( "selector-empty-id", "jQuery( '#' ) is not a valid selector" ); - args[ 0 ] = []; - } - - return oldInit.apply( this, args ); -}, "selector-empty-id" ); - -// This is already done in Core but the above patch will lose this assignment -// so we need to redo it. It doesn't matter whether the patch is enabled or not -// as the method is always going to be a Migrate-created wrapper. -jQuery.fn.init.prototype = jQuery.fn; - -migratePatchFunc( jQuery, "find", function( selector ) { - var args = Array.prototype.slice.call( arguments ); - - // Support: PhantomJS 1.x - // String#match fails to match when used with a //g RegExp, only on some strings - if ( typeof selector === "string" && rattrHashTest.test( selector ) ) { - - // The nonstandard and undocumented unquoted-hash was removed in jQuery 1.12.0 - // First see if qS thinks it's a valid selector, if so avoid a false positive - try { - window.document.querySelector( selector ); - } catch ( err1 ) { - - // Didn't *look* valid to qSA, warn and try quoting what we think is the value - selector = selector.replace( rattrHashGlob, function( _, attr, op, value ) { - return "[" + attr + op + "\"" + value + "\"]"; - } ); - - // If the regexp *may* have created an invalid selector, don't update it - // Note that there may be false alarms if selector uses jQuery extensions - try { - window.document.querySelector( selector ); - migrateWarn( "selector-hash", - "Attribute selector with '#' must be quoted: " + args[ 0 ] ); - args[ 0 ] = selector; - } catch ( err2 ) { - migrateWarn( "selector-hash", - "Attribute selector with '#' was not fixed: " + args[ 0 ] ); - } - } - } - - return oldFind.apply( this, args ); -}, "selector-hash" ); - -// Copy properties attached to original jQuery.find method (e.g. .attr, .isXML) -for ( findProp in oldFind ) { - if ( Object.prototype.hasOwnProperty.call( oldFind, findProp ) ) { - jQuery.find[ findProp ] = oldFind[ findProp ]; - } -} - // The number of elements contained in the matched element set migratePatchAndWarnFunc( jQuery.fn, "size", function() { return this.length; @@ -176,11 +98,10 @@ if ( jQueryVersionSince( "3.3.0" ) ) { }, "type", "jQuery.type is deprecated" ); - migratePatchAndWarnFunc( jQuery, "isFunction", - function( obj ) { - return typeof obj === "function"; - }, "isFunction", - "jQuery.isFunction() is deprecated" ); + migratePatchAndWarnFunc( jQuery, "isFunction", function( obj ) { + return isFunction( obj ); + }, "isFunction", + "jQuery.isFunction() is deprecated" ); migratePatchAndWarnFunc( jQuery, "isWindow", function( obj ) { @@ -193,46 +114,7 @@ if ( jQueryVersionSince( "3.3.0" ) ) { // arguments. // jQuery.proxy is deprecated to promote standards (specifically Function#bind) // However, it is not slated for removal any time soon - migratePatchAndWarnFunc( jQuery, "proxy", - function( fn, context ) { - var tmp, args, proxy; - - if ( typeof context === "string" ) { - tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - args = slice.call( arguments, 2 ); - proxy = function() { - return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || jQuery.guid++; - - return proxy; - }, "proxy", - "jQuery.proxy() is deprecated" - ); - -} - -if ( jQueryVersionSince( "4.0.0" ) ) { + migratePatchAndWarnFunc( jQuery, "proxy", jQuery.proxy, + "proxy", "DEPRECATED: jQuery.proxy()" ); - // `push`, `sort` & `splice` are used internally by jQuery <4, so we only - // warn in jQuery 4+. - migrateWarnProp( jQuery.fn, "push", push, "push", - "jQuery.fn.push() is deprecated and removed; use .add or convert to an array" ); - migrateWarnProp( jQuery.fn, "sort", sort, "sort", - "jQuery.fn.sort() is deprecated and removed; convert to an array before sorting" ); - migrateWarnProp( jQuery.fn, "splice", splice, "splice", - "jQuery.fn.splice() is deprecated and removed; use .slice or .not with .eq" ); } diff --git a/src/jquery/css.js b/src/jquery/css.js index 2ae10feb..f06853fc 100644 --- a/src/jquery/css.js +++ b/src/jquery/css.js @@ -2,7 +2,7 @@ import { jQueryVersionSince } from "../compareVersions.js"; import { migrateWarn, migratePatchFunc } from "../main.js"; import { camelCase } from "../utils.js"; -var origFnCss, internalCssNumber, +var origFnCss, internalSwapCall = false, ralphaStart = /^[a-z]/, @@ -80,71 +80,6 @@ if ( jQueryVersionSince( "3.4.0" ) && typeof Proxy !== "undefined" ) { } ); } -// In jQuery >=4 where jQuery.cssNumber is missing fill it with the latest 3.x version: -// https://github.com/jquery/jquery/blob/3.7.1/src/css.js#L216-L246 -// This way, number values for the CSS properties below won't start triggering -// Migrate warnings when jQuery gets updated to >=4.0.0 (gh-438). -if ( jQueryVersionSince( "4.0.0" ) ) { - - // We need to keep this as a local variable as we need it internally - // in a `jQuery.fn.css` patch and this usage shouldn't warn. - internalCssNumber = { - animationIterationCount: true, - aspectRatio: true, - borderImageSlice: true, - columnCount: true, - flexGrow: true, - flexShrink: true, - fontWeight: true, - gridArea: true, - gridColumn: true, - gridColumnEnd: true, - gridColumnStart: true, - gridRow: true, - gridRowEnd: true, - gridRowStart: true, - lineHeight: true, - opacity: true, - order: true, - orphans: true, - scale: true, - widows: true, - zIndex: true, - zoom: true, - - // SVG-related - fillOpacity: true, - floodOpacity: true, - stopOpacity: true, - strokeMiterlimit: true, - strokeOpacity: true - }; - - if ( typeof Proxy !== "undefined" ) { - jQuery.cssNumber = new Proxy( internalCssNumber, { - get: function() { - migrateWarn( "css-number", "jQuery.cssNumber is deprecated" ); - return Reflect.get.apply( this, arguments ); - }, - set: function() { - migrateWarn( "css-number", "jQuery.cssNumber is deprecated" ); - return Reflect.set.apply( this, arguments ); - } - } ); - } else { - - // Support: IE 9-11+ - // IE doesn't support proxies, but we still want to restore the legacy - // jQuery.cssNumber there. - jQuery.cssNumber = internalCssNumber; - } -} else { - - // Make `internalCssNumber` defined for jQuery <4 as well as it's needed - // in the `jQuery.fn.css` patch below. - internalCssNumber = jQuery.cssNumber; -} - function isAutoPx( prop ) { // The first test is used to ensure that: @@ -170,9 +105,7 @@ migratePatchFunc( jQuery.fn, "css", function( name, value ) { if ( typeof value === "number" ) { camelName = camelCase( name ); - // Use `internalCssNumber` to avoid triggering our warnings in this - // internal check. - if ( !isAutoPx( camelName ) && !internalCssNumber[ camelName ] ) { + if ( !isAutoPx( camelName ) && !jQuery.cssNumber[ camelName ] ) { migrateWarn( "css-number", "Number-typed values are deprecated for jQuery.fn.css( \"" + name + "\", value )" ); diff --git a/src/jquery/deferred.js b/src/jquery/deferred.js index 7f036efe..bb78cd3e 100644 --- a/src/jquery/deferred.js +++ b/src/jquery/deferred.js @@ -3,7 +3,6 @@ import { migratePatchAndWarnFunc, migrateWarn } from "../main.js"; -import { jQueryVersionSince } from "../compareVersions.js"; // Support jQuery slim which excludes the deferred module in jQuery 4.0+ if ( jQuery.Deferred ) { @@ -80,13 +79,8 @@ Object.defineProperty( jQuery.Deferred, "getStackHook", { get: function() { if ( jQuery.migrateIsPatchEnabled( "deferred-getStackHook" ) ) { - // jQuery 3.x checks `getStackHook` if `getErrorHook` missing; - // don't warn on the getter there. - if ( jQueryVersionSince( "4.0.0" ) ) { - migrateWarn( "deferred-getStackHook", - "jQuery.Deferred.getStackHook is deprecated; " + - "use jQuery.Deferred.getErrorHook" ); - } + // jQuery 3.x checks `getStackHook` if `getErrorHook` is missing, + // so don't warn on the getter. return jQuery.Deferred.getErrorHook; } else { return unpatchedGetStackHookValue; diff --git a/src/jquery/event.js b/src/jquery/event.js index 5a5ea9a1..c0cce65e 100644 --- a/src/jquery/event.js +++ b/src/jquery/event.js @@ -96,13 +96,9 @@ jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + function( _i, name ) { // Handle event binding - migratePatchAndWarnFunc( jQuery.fn, name, function( data, fn ) { - return arguments.length > 0 ? - this.on( name, null, data, fn ) : - this.trigger( name ); - }, - "shorthand-deprecated-v3", - "jQuery.fn." + name + "() event shorthand is deprecated" ); + migratePatchAndWarnFunc( jQuery.fn, name, jQuery.fn[ name ], "shorthand-deprecated-v3", + "DEPRECATED: jQuery.fn." + name + "() event shorthand" ); + } ); // Trigger "ready" event only once, on document ready @@ -118,6 +114,11 @@ jQuery.event.special.ready = { } }; +// Support: jQuery <3.2.0 only +// jQuery 3.0.x & 3.1.x used to not include the deprecated module in the slim build. +// To maintain compatibility with those versions, we need to reimplement APIs +// deprecated in them. +// See https://github.com/jquery/jquery/blob/3.1.1/src/deprecated.js migratePatchAndWarnFunc( jQuery.fn, "bind", function( types, data, fn ) { return this.on( types, null, data, fn ); }, "pre-on-methods", "jQuery.fn.bind() is deprecated" ); diff --git a/src/jquery/selector.js b/src/jquery/selector.js index 44237d30..c1625a12 100644 --- a/src/jquery/selector.js +++ b/src/jquery/selector.js @@ -1,6 +1,75 @@ import { jQueryVersionSince } from "../compareVersions.js"; import { migratePatchFunc, migrateWarnProp, migrateWarn } from "../main.js"; +var findProp, + oldInit = jQuery.fn.init, + oldFind = jQuery.find, + + rattrHashTest = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/, + rattrHashGlob = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/g; + +migratePatchFunc( jQuery.fn, "init", function( arg1 ) { + var args = Array.prototype.slice.call( arguments ); + + if ( jQuery.migrateIsPatchEnabled( "selector-empty-id" ) && + typeof arg1 === "string" && arg1 === "#" ) { + + // JQuery( "#" ) is a bogus ID selector, but it returned an empty set + // before jQuery 3.0 + migrateWarn( "selector-empty-id", "jQuery( '#' ) is not a valid selector" ); + args[ 0 ] = []; + } + + return oldInit.apply( this, args ); +}, "selector-empty-id" ); + +// This is already done in Core but the above patch will lose this assignment +// so we need to redo it. It doesn't matter whether the patch is enabled or not +// as the method is always going to be a Migrate-created wrapper. +jQuery.fn.init.prototype = jQuery.fn; + +migratePatchFunc( jQuery, "find", function( selector ) { + var args = Array.prototype.slice.call( arguments ); + + // Support: PhantomJS 1.x + // String#match fails to match when used with a //g RegExp, only on some strings + if ( typeof selector === "string" && rattrHashTest.test( selector ) ) { + + // The nonstandard and undocumented unquoted-hash was removed in jQuery 1.12.0 + // First see if qS thinks it's a valid selector, if so avoid a false positive + try { + window.document.querySelector( selector ); + } catch ( err1 ) { + + // Didn't *look* valid to qSA, warn and try quoting what we think is the value + selector = selector.replace( rattrHashGlob, function( _, attr, op, value ) { + return "[" + attr + op + "\"" + value + "\"]"; + } ); + + // If the regexp *may* have created an invalid selector, don't update it + // Note that there may be false alarms if selector uses jQuery extensions + try { + window.document.querySelector( selector ); + migrateWarn( "selector-hash", + "Attribute selector with '#' must be quoted: " + args[ 0 ] ); + args[ 0 ] = selector; + } catch ( err2 ) { + migrateWarn( "selector-hash", + "Attribute selector with '#' was not fixed: " + args[ 0 ] ); + } + } + } + + return oldFind.apply( this, args ); +}, "selector-hash" ); + +// Copy properties attached to original jQuery.find method (e.g. .attr, .isXML) +for ( findProp in oldFind ) { + if ( Object.prototype.hasOwnProperty.call( oldFind, findProp ) ) { + jQuery.find[ findProp ] = oldFind[ findProp ]; + } +} + // Now jQuery.expr.pseudos is the standard incantation migrateWarnProp( jQuery.expr, "filters", jQuery.expr.pseudos, "expr-pre-pseudos", "jQuery.expr.filters is deprecated; use jQuery.expr.pseudos" ); diff --git a/src/main.js b/src/main.js index ca6ce5c7..909b6203 100644 --- a/src/main.js +++ b/src/main.js @@ -10,10 +10,10 @@ if ( !window.console || !window.console.log ) { return; } -// Need jQuery 3.x-4.x and no older Migrate loaded +// Need jQuery 3.x and no older Migrate loaded if ( !jQuery || !jQueryVersionSince( "3.0.0" ) || - jQueryVersionSince( "5.0.0" ) ) { - window.console.log( "JQMIGRATE: jQuery 3.x-4.x REQUIRED" ); + jQueryVersionSince( "4.0.0" ) ) { + window.console.log( "JQMIGRATE: jQuery 3.x REQUIRED" ); } if ( jQuery.migrateWarnings ) { window.console.log( "JQMIGRATE: Migrate plugin loaded multiple times" ); diff --git a/test/data/ajax-jsonp-callback-name.html b/test/data/ajax-jsonp-callback-name.html index 2d10331a..fd9766b9 100644 --- a/test/data/ajax-jsonp-callback-name.html +++ b/test/data/ajax-jsonp-callback-name.html @@ -7,7 +7,7 @@