Skip to content

Commit 05a05b7

Browse files
committed
Core: Support selectively disabling Migrate patches
This adds three new APIs: * `jQuery.migrateDisablePatches` * `jQuery.migrateEnablePatches` * `jQuery.migrateIsPatchEnabled` allowing to selectively disable/re-enable patches in runtime. Source code is refactored to avoid manually overwriting jQuery methods in favor of using `migratePatchAndWarnFunc` or `migratePatchFunc` which cooperate with above methods. The `jQuery.UNSAFE_restoreLegacyHtmlPrefilter` API, introduced in Migrate 3.2.0, is now deprecated in favor of calling: ```js jQuery.migrateEnablePatches( "self-closed-tags" ); ``` The commit also reorganizes test code a bit, grouping modules testing patches to jQuery modules in a separate directory and extracting tests of Migrate APIs out of `core.js` to a separate `migrate.js` file. Helper files are now put in `test/data/` and unit tests in `test/unit/`; jQuery patch tests are in `test/unit/jquery/`. Fixes gh-449
1 parent 5c29fca commit 05a05b7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+557
-361
lines changed

Gruntfile.js

+15-14
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,21 @@ module.exports = function( grunt ) {
1111
"dist/jquery-migrate.min.js",
1212
"test/data/compareVersions.js",
1313

14-
"test/testinit.js",
15-
"test/migrate.js",
16-
"test/core.js",
17-
"test/ajax.js",
18-
"test/attributes.js",
19-
"test/css.js",
20-
"test/data.js",
21-
"test/deferred.js",
22-
"test/effects.js",
23-
"test/event.js",
24-
"test/manipulation.js",
25-
"test/offset.js",
26-
"test/serialize.js",
27-
"test/traversing.js",
14+
"test/data/testinit.js",
15+
"test/data/test-utils.js",
16+
"test/unit/migrate.js",
17+
"test/unit/jquery/core.js",
18+
"test/unit/jquery/ajax.js",
19+
"test/unit/jquery/attributes.js",
20+
"test/unit/jquery/css.js",
21+
"test/unit/jquery/data.js",
22+
"test/unit/jquery/deferred.js",
23+
"test/unit/jquery/effects.js",
24+
"test/unit/jquery/event.js",
25+
"test/unit/jquery/manipulation.js",
26+
"test/unit/jquery/offset.js",
27+
"test/unit/jquery/serialize.js",
28+
"test/unit/jquery/traversing.js",
2829

2930
{ pattern: "dist/jquery-migrate.js", included: false, served: true },
3031
{ pattern: "test/**/*.@(js|json|css|jpg|html|xml)", included: false, served: true }

README.md

+8
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ This plugin adds some properties to the `jQuery` object that can be used to prog
5656

5757
`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.
5858

59+
`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.
60+
61+
`jQuery.migrateDisablePatches`: Disables patches by their codes.
62+
63+
`jQuery.migrateIsPatchEnabled`: Returns `true` if a patch of a provided code is enabled and `false` otherwise.
64+
65+
`jQuery.UNSAFE_restoreLegacyHtmlPrefilter`: A deprecated alias of `jQuery.migrateEnablePatches( "self-closed-tags" )`
66+
5967
## Reporting problems
6068

6169
Bugs that only occur when the jQuery Migrate plugin is used should be reported in the [jQuery Migrate Issue Tracker](https://github.com/jquery/jquery-migrate/issues) and should be accompanied by an executable test case that demonstrates the bug. The easiest way to do this is via an online test tool such as [jsFiddle.net](https://jsFiddle.net/) or [jsbin.com](https://jsbin.com). Use the development version when you are reporting bugs.

src/disablePatches.js

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// A map from disabled patch codes to `true`. This should really
2+
// be a `Set` but those are unsupported in IE.
3+
var disabledPatches = Object.create( null );
4+
5+
// Don't apply patches for specified codes. Helpful for code bases
6+
// where some Migrate warnings have been addressed and it's desirable
7+
// to avoid needless patches or false positives.
8+
jQuery.migrateDisablePatches = function() {
9+
var i;
10+
for ( i = 0; i < arguments.length; i++ ) {
11+
disabledPatches[ arguments[ i ] ] = true;
12+
}
13+
};
14+
15+
// Allow enabling patches disabled via `jQuery.migrateDisablePatches`.
16+
// Helpful if you want to disable a patch only for some code that won't
17+
// be updated soon to be able to focus on other warnings - and enable it
18+
// immediately after such a call:
19+
// ```js
20+
// jQuery.migrateDisablePatches( "workaroundA" );
21+
// elem.pluginViolatingWarningA( "pluginMethod" );
22+
// jQuery.migrateEnablePatches( "workaroundA" );
23+
// ```
24+
jQuery.migrateEnablePatches = function() {
25+
var i;
26+
for ( i = 0; i < arguments.length; i++ ) {
27+
delete disabledPatches[ arguments[ i ] ];
28+
}
29+
};
30+
31+
jQuery.migrateIsPatchEnabled = function( patchCode ) {
32+
return !disabledPatches[ patchCode ];
33+
};

src/jquery/ajax.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
import { jQueryVersionSince } from "../compareVersions.js";
2-
import { migrateWarn, migrateWarnFunc } from "../main.js";
2+
import { migrateWarn, migratePatchAndWarnFunc, migratePatchFunc } from "../main.js";
33

44
// Support jQuery slim which excludes the ajax module
55
if ( jQuery.ajax ) {
66

77
var oldAjax = jQuery.ajax,
88
rjsonp = /(=)\?(?=&|$)|\?\?/;
99

10-
jQuery.ajax = function( ) {
10+
migratePatchFunc( jQuery, "ajax", function() {
1111
var jQXHR = oldAjax.apply( this, arguments );
1212

1313
// Be sure we got a jQXHR (e.g., not sync)
1414
if ( jQXHR.promise ) {
15-
migrateWarnFunc( jQXHR, "success", jQXHR.done,
15+
migratePatchAndWarnFunc( jQXHR, "success", jQXHR.done, "jqXHR-methods",
1616
"jQXHR.success is deprecated and removed" );
17-
migrateWarnFunc( jQXHR, "error", jQXHR.fail,
17+
migratePatchAndWarnFunc( jQXHR, "error", jQXHR.fail, "jqXHR-methods",
1818
"jQXHR.error is deprecated and removed" );
19-
migrateWarnFunc( jQXHR, "complete", jQXHR.always,
19+
migratePatchAndWarnFunc( jQXHR, "complete", jQXHR.always, "jqXHR-methods",
2020
"jQXHR.complete is deprecated and removed" );
2121
}
2222

2323
return jQXHR;
24-
};
24+
}, "jqXHR-methods" );
2525

2626
// Only trigger the logic in jQuery <4 as the JSON-to-JSONP auto-promotion
2727
// behavior is gone in jQuery 4.0 and as it has security implications, we don't
@@ -40,7 +40,7 @@ if ( !jQueryVersionSince( "4.0.0" ) ) {
4040
.indexOf( "application/x-www-form-urlencoded" ) === 0 &&
4141
rjsonp.test( s.data )
4242
) ) {
43-
migrateWarn( "JSON-to-JSONP auto-promotion is deprecated" );
43+
migrateWarn( "jsonp-promotion", "JSON-to-JSONP auto-promotion is deprecated" );
4444
}
4545
} );
4646
}

src/jquery/attributes.js

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,32 @@
1-
import { migrateWarn } from "../main.js";
1+
import { migratePatchFunc, migrateWarn } from "../main.js";
22

33
var oldRemoveAttr = jQuery.fn.removeAttr,
44
oldToggleClass = jQuery.fn.toggleClass,
55
rmatchNonSpace = /\S+/g;
66

7-
jQuery.fn.removeAttr = function( name ) {
7+
migratePatchFunc( jQuery.fn, "removeAttr", function( name ) {
88
var self = this;
99

1010
jQuery.each( name.match( rmatchNonSpace ), function( _i, attr ) {
1111
if ( jQuery.expr.match.bool.test( attr ) ) {
12-
migrateWarn( "jQuery.fn.removeAttr no longer sets boolean properties: " + attr );
12+
migrateWarn( "removeAttr-bool",
13+
"jQuery.fn.removeAttr no longer sets boolean properties: " + attr );
1314
self.prop( attr, false );
1415
}
1516
} );
1617

1718
return oldRemoveAttr.apply( this, arguments );
18-
};
19+
}, "removeAttr-bool" );
1920

20-
jQuery.fn.toggleClass = function( state ) {
21+
migratePatchFunc( jQuery.fn, "toggleClass", function( state ) {
2122

2223
// Only deprecating no-args or single boolean arg
2324
if ( state !== undefined && typeof state !== "boolean" ) {
25+
2426
return oldToggleClass.apply( this, arguments );
2527
}
2628

27-
migrateWarn( "jQuery.fn.toggleClass( boolean ) is deprecated" );
29+
migrateWarn( "toggleClass-bool", "jQuery.fn.toggleClass( boolean ) is deprecated" );
2830

2931
// Toggle entire class name of each element
3032
return this.each( function() {
@@ -46,4 +48,4 @@ jQuery.fn.toggleClass = function( state ) {
4648
);
4749
}
4850
} );
49-
};
51+
}, "toggleClass-bool" );

src/jquery/core.js

+47-33
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import { jQueryVersionSince } from "../compareVersions.js";
2-
import { migrateWarn, migrateWarnFunc, migrateWarnProp } from "../main.js";
2+
import {
3+
migratePatchFunc,
4+
migrateWarn,
5+
migratePatchAndWarnFunc,
6+
migrateWarnProp
7+
} from "../main.js";
8+
import "../disablePatches.js";
39

410
var findProp,
511
class2type = {},
@@ -13,21 +19,27 @@ var findProp,
1319
// Make sure we trim BOM and NBSP
1420
rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
1521

16-
jQuery.fn.init = function( arg1 ) {
22+
migratePatchFunc( jQuery.fn, "init", function( arg1 ) {
1723
var args = Array.prototype.slice.call( arguments );
1824

19-
if ( typeof arg1 === "string" && arg1 === "#" ) {
25+
if ( jQuery.migrateIsPatchEnabled( "selector-empty-id" ) &&
26+
typeof arg1 === "string" && arg1 === "#" ) {
2027

21-
// JQuery( "#" ) is a bogus ID selector, but it returned an empty set before jQuery 3.0
22-
migrateWarn( "jQuery( '#' ) is not a valid selector" );
28+
// JQuery( "#" ) is a bogus ID selector, but it returned an empty set
29+
// before jQuery 3.0
30+
migrateWarn( "selector-empty-id", "jQuery( '#' ) is not a valid selector" );
2331
args[ 0 ] = [];
2432
}
2533

2634
return oldInit.apply( this, args );
27-
};
35+
}, "selector-empty-id" );
36+
37+
// This is already done in Core but the above patch will lose this assignment
38+
// so we need to redo it. It doesn't matter whether the patch is enabled or not
39+
// as the method is always going to be a Migrate-created wrapper.
2840
jQuery.fn.init.prototype = jQuery.fn;
2941

30-
jQuery.find = function( selector ) {
42+
migratePatchFunc( jQuery, "find", function( selector ) {
3143
var args = Array.prototype.slice.call( arguments );
3244

3345
// Support: PhantomJS 1.x
@@ -49,16 +61,18 @@ jQuery.find = function( selector ) {
4961
// Note that there may be false alarms if selector uses jQuery extensions
5062
try {
5163
window.document.querySelector( selector );
52-
migrateWarn( "Attribute selector with '#' must be quoted: " + args[ 0 ] );
64+
migrateWarn( "selector-hash",
65+
"Attribute selector with '#' must be quoted: " + args[ 0 ] );
5366
args[ 0 ] = selector;
5467
} catch ( err2 ) {
55-
migrateWarn( "Attribute selector with '#' was not fixed: " + args[ 0 ] );
68+
migrateWarn( "selector-hash",
69+
"Attribute selector with '#' was not fixed: " + args[ 0 ] );
5670
}
5771
}
5872
}
5973

6074
return oldFind.apply( this, args );
61-
};
75+
}, "selector-hash" );
6276

6377
// Copy properties attached to original jQuery.find method (e.g. .attr, .isXML)
6478
for ( findProp in oldFind ) {
@@ -68,53 +82,53 @@ for ( findProp in oldFind ) {
6882
}
6983

7084
// The number of elements contained in the matched element set
71-
migrateWarnFunc( jQuery.fn, "size", function() {
85+
migratePatchAndWarnFunc( jQuery.fn, "size", function() {
7286
return this.length;
73-
},
87+
}, "size",
7488
"jQuery.fn.size() is deprecated and removed; use the .length property" );
7589

76-
migrateWarnFunc( jQuery, "parseJSON", function() {
90+
migratePatchAndWarnFunc( jQuery, "parseJSON", function() {
7791
return JSON.parse.apply( null, arguments );
78-
},
92+
}, "parseJSON",
7993
"jQuery.parseJSON is deprecated; use JSON.parse" );
8094

81-
migrateWarnFunc( jQuery, "holdReady", jQuery.holdReady,
82-
"jQuery.holdReady is deprecated" );
95+
migratePatchAndWarnFunc( jQuery, "holdReady", jQuery.holdReady,
96+
"holdReady", "jQuery.holdReady is deprecated" );
8397

84-
migrateWarnFunc( jQuery, "unique", jQuery.uniqueSort,
85-
"jQuery.unique is deprecated; use jQuery.uniqueSort" );
98+
migratePatchAndWarnFunc( jQuery, "unique", jQuery.uniqueSort,
99+
"unique", "jQuery.unique is deprecated; use jQuery.uniqueSort" );
86100

87101
// Now jQuery.expr.pseudos is the standard incantation
88-
migrateWarnProp( jQuery.expr, "filters", jQuery.expr.pseudos,
102+
migrateWarnProp( jQuery.expr, "filters", jQuery.expr.pseudos, "expr-pre-pseudos",
89103
"jQuery.expr.filters is deprecated; use jQuery.expr.pseudos" );
90-
migrateWarnProp( jQuery.expr, ":", jQuery.expr.pseudos,
104+
migrateWarnProp( jQuery.expr, ":", jQuery.expr.pseudos, "expr-pre-pseudos",
91105
"jQuery.expr[':'] is deprecated; use jQuery.expr.pseudos" );
92106

93107
// Prior to jQuery 3.1.1 there were internal refs so we don't warn there
94108
if ( jQueryVersionSince( "3.1.1" ) ) {
95-
migrateWarnFunc( jQuery, "trim", function( text ) {
109+
migratePatchAndWarnFunc( jQuery, "trim", function( text ) {
96110
return text == null ?
97111
"" :
98112
( text + "" ).replace( rtrim, "" );
99-
},
113+
}, "trim",
100114
"jQuery.trim is deprecated; use String.prototype.trim" );
101115
}
102116

103117
// Prior to jQuery 3.2 there were internal refs so we don't warn there
104118
if ( jQueryVersionSince( "3.2.0" ) ) {
105-
migrateWarnFunc( jQuery, "nodeName", function( elem, name ) {
119+
migratePatchAndWarnFunc( jQuery, "nodeName", function( elem, name ) {
106120
return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
107-
},
121+
}, "nodeName",
108122
"jQuery.nodeName is deprecated" );
109123

110-
migrateWarnFunc( jQuery, "isArray", Array.isArray,
124+
migratePatchAndWarnFunc( jQuery, "isArray", Array.isArray, "isArray",
111125
"jQuery.isArray is deprecated; use Array.isArray"
112126
);
113127
}
114128

115129
if ( jQueryVersionSince( "3.3.0" ) ) {
116130

117-
migrateWarnFunc( jQuery, "isNumeric", function( obj ) {
131+
migratePatchAndWarnFunc( jQuery, "isNumeric", function( obj ) {
118132

119133
// As of jQuery 3.0, isNumeric is limited to
120134
// strings and numbers (primitives or objects)
@@ -126,7 +140,7 @@ if ( jQueryVersionSince( "3.3.0" ) ) {
126140
// ...but misinterprets leading-number strings, e.g. hex literals ("0x...")
127141
// subtraction forces infinities to NaN
128142
!isNaN( obj - parseFloat( obj ) );
129-
},
143+
}, "isNumeric",
130144
"jQuery.isNumeric() is deprecated"
131145
);
132146

@@ -137,7 +151,7 @@ if ( jQueryVersionSince( "3.3.0" ) ) {
137151
class2type[ "[object " + name + "]" ] = name.toLowerCase();
138152
} );
139153

140-
migrateWarnFunc( jQuery, "type", function( obj ) {
154+
migratePatchAndWarnFunc( jQuery, "type", function( obj ) {
141155
if ( obj == null ) {
142156
return obj + "";
143157
}
@@ -146,19 +160,19 @@ if ( jQueryVersionSince( "3.3.0" ) ) {
146160
return typeof obj === "object" || typeof obj === "function" ?
147161
class2type[ Object.prototype.toString.call( obj ) ] || "object" :
148162
typeof obj;
149-
},
163+
}, "type",
150164
"jQuery.type is deprecated" );
151165

152-
migrateWarnFunc( jQuery, "isFunction",
166+
migratePatchAndWarnFunc( jQuery, "isFunction",
153167
function( obj ) {
154168
return typeof obj === "function";
155-
},
169+
}, "isFunction",
156170
"jQuery.isFunction() is deprecated" );
157171

158-
migrateWarnFunc( jQuery, "isWindow",
172+
migratePatchAndWarnFunc( jQuery, "isWindow",
159173
function( obj ) {
160174
return obj != null && obj === obj.window;
161-
},
175+
}, "isWindow",
162176
"jQuery.isWindow() is deprecated"
163177
);
164178
}

0 commit comments

Comments
 (0)