@automattic/eslint-config-target-es 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/README.md +5 -1
- package/SECURITY.md +11 -2
- package/package.json +6 -6
- package/src/funcs.js +19 -83
- package/src/needsCheck.js +151 -0
- package/src/rulesMap.js +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,24 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.1.0] - 2024-02-07
|
|
9
|
+
### Added
|
|
10
|
+
- All versions indicated by browserslist are now checked, not just the lowest. Added `getAllBrowsers` function to support this. [#31658]
|
|
11
|
+
- Support for more complex MDN data:
|
|
12
|
+
* Multiple support statements are now all checked. Previously only the first (most recent) was, which may have missed cases where support was backported.
|
|
13
|
+
* `version_removed` is now checked.
|
|
14
|
+
* Ranged versions (≤) are now handled.
|
|
15
|
+
* `prefix`, `alternative_name`, and `flags` now indicate (possible) lack of support. [#31658]
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- Updated package dependencies.
|
|
19
|
+
|
|
20
|
+
### Deprecated
|
|
21
|
+
- Deprecated `getBrowsers` function in favor of the new `getAllBrowsers`. [#31658]
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
- Apparently MDN data considers "preview" a version, but didn't think that worth documenting. Handle it. [#31816]
|
|
25
|
+
|
|
8
26
|
## [2.0.0] - 2023-06-26
|
|
9
27
|
### Changed
|
|
10
28
|
- As `eslint-plugin-es` appears to be abandoned, change to using `eslint-plugin-es-x`. [#31556]
|
|
@@ -41,6 +59,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
41
59
|
### Added
|
|
42
60
|
- Initial release.
|
|
43
61
|
|
|
62
|
+
[2.1.0]: https://github.com/Automattic/eslint-config-target-es/compare/2.0.0...2.1.0
|
|
44
63
|
[2.0.0]: https://github.com/Automattic/eslint-config-target-es/compare/1.0.6...2.0.0
|
|
45
64
|
[1.0.6]: https://github.com/Automattic/eslint-config-target-es/compare/1.0.5...1.0.6
|
|
46
65
|
[1.0.5]: https://github.com/Automattic/eslint-config-target-es/compare/1.0.4...1.0.5
|
package/README.md
CHANGED
|
@@ -61,10 +61,14 @@ to avoid your standard eslintrc and eslintignore and to avoid errors from any in
|
|
|
61
61
|
|
|
62
62
|
You can import or require `@automattic/eslint-config-target-es/functions` to gain access to some functions that can be used to build your own configuration.
|
|
63
63
|
|
|
64
|
-
As browserslist and MDN use different browser codes, `
|
|
64
|
+
As browserslist and MDN use different browser codes, `getAllBrowsers( { query: } )` will take a browserslist query and return an object with the MDN browser codes and the matched versions for each.
|
|
65
65
|
|
|
66
66
|
`getRules( { query:, builtins: } )` will return the rules config. Set `builtins` true for "builtins", false for "language", or null/undefined for "all".
|
|
67
67
|
|
|
68
|
+
### Caveats
|
|
69
|
+
|
|
70
|
+
Some browsers supported by browserslist are not availble in the MDN data (e.g. Opera Mini) or are no longer being updated (e.g. Internet Explorer). In cases like these where no data is available, features are assumed to be supported. Set the environment variable `DEBUG=@automattic/eslint-config-target-es:warn` to generate messages when this happens.
|
|
71
|
+
|
|
68
72
|
## Security
|
|
69
73
|
|
|
70
74
|
Need to report a security vulnerability? Go to [https://automattic.com/security/](https://automattic.com/security/) or directly to our security bug bounty site [https://hackerone.com/automattic](https://hackerone.com/automattic).
|
package/SECURITY.md
CHANGED
|
@@ -4,11 +4,20 @@ Full details of the Automattic Security Policy can be found on [automattic.com](
|
|
|
4
4
|
|
|
5
5
|
## Supported Versions
|
|
6
6
|
|
|
7
|
-
Generally, only the latest version of Jetpack
|
|
7
|
+
Generally, only the latest version of Jetpack and its associated plugins have continued support. If a critical vulnerability is found in the current version of a plugin, we may opt to backport any patches to previous versions.
|
|
8
8
|
|
|
9
9
|
## Reporting a Vulnerability
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Our HackerOne program covers the below plugin software, as well as a variety of related projects and infrastructure:
|
|
12
|
+
|
|
13
|
+
* [Jetpack](https://jetpack.com/)
|
|
14
|
+
* Jetpack Backup
|
|
15
|
+
* Jetpack Boost
|
|
16
|
+
* Jetpack CRM
|
|
17
|
+
* Jetpack Protect
|
|
18
|
+
* Jetpack Search
|
|
19
|
+
* Jetpack Social
|
|
20
|
+
* Jetpack VideoPress
|
|
12
21
|
|
|
13
22
|
**For responsible disclosure of security issues and to be eligible for our bug bounty program, please submit your report via the [HackerOne](https://hackerone.com/automattic) portal.**
|
|
14
23
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/eslint-config-target-es",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "ESLint sharable config to activate eslint-plugin-es checks based on browserslist targets.",
|
|
5
5
|
"homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/eslint-config-target-es/README.md#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -17,16 +17,16 @@
|
|
|
17
17
|
"test": "jest tests"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@mdn/browser-compat-data": "5.
|
|
20
|
+
"@mdn/browser-compat-data": "5.3.28",
|
|
21
21
|
"browserslist": "^4.17.6",
|
|
22
22
|
"debug": "^4.3.2",
|
|
23
23
|
"semver": "^7.3.5"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@wordpress/browserslist-config": "5.
|
|
27
|
-
"eslint": "8.
|
|
28
|
-
"eslint-plugin-es-x": "7.
|
|
29
|
-
"jest": "29.
|
|
26
|
+
"@wordpress/browserslist-config": "5.33.0",
|
|
27
|
+
"eslint": "8.51.0",
|
|
28
|
+
"eslint-plugin-es-x": "7.2.0",
|
|
29
|
+
"jest": "29.7.0"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
32
|
"eslint": ">=4.19.1",
|
package/src/funcs.js
CHANGED
|
@@ -1,22 +1,20 @@
|
|
|
1
|
-
const mdn = require( '@mdn/browser-compat-data' );
|
|
2
1
|
const browserslist = require( 'browserslist' );
|
|
3
2
|
const debug = require( 'debug' );
|
|
4
3
|
const { rules: esRules } = require( 'eslint-plugin-es-x' );
|
|
5
4
|
const semver = require( 'semver' );
|
|
6
5
|
const browsersMap = require( './browsersMap.js' );
|
|
7
|
-
const
|
|
6
|
+
const { needsCheck } = require( './needsCheck.js' );
|
|
8
7
|
|
|
9
8
|
const warn = debug( '@automattic/eslint-config-target-es:warn' );
|
|
10
|
-
const debuglog = debug( '@automattic/eslint-config-target-es:debug' );
|
|
11
9
|
|
|
12
10
|
/**
|
|
13
11
|
* Get the list of supported browsers.
|
|
14
12
|
*
|
|
15
13
|
* @param {object} options - Options.
|
|
16
14
|
* @param {string} options.query - Browserslist query.
|
|
17
|
-
* @returns {object} Browsers mapped to versions.
|
|
15
|
+
* @returns {object} Browsers mapped to arrays of versions.
|
|
18
16
|
*/
|
|
19
|
-
function
|
|
17
|
+
function getAllBrowsers( options = {} ) {
|
|
20
18
|
const browsers = {};
|
|
21
19
|
for ( const b of browserslist( options.query ) ) {
|
|
22
20
|
const m = b.match( /^([a-z_]+) (all|[0-9.]+)(-.*)?$/ );
|
|
@@ -33,92 +31,29 @@ function getBrowsers( options = {} ) {
|
|
|
33
31
|
continue;
|
|
34
32
|
}
|
|
35
33
|
const ver = m[ 2 ] === 'all' ? '0.0.0' : semver.coerce( m[ 2 ] ).version;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
browsers[ browser ] ||= [];
|
|
35
|
+
browsers[ browser ].push( ver );
|
|
36
|
+
browsers[ browser ].sort( semver.compare );
|
|
39
37
|
}
|
|
40
38
|
return browsers;
|
|
41
39
|
}
|
|
42
40
|
|
|
43
41
|
/**
|
|
44
|
-
*
|
|
42
|
+
* Get the list of supported browsers.
|
|
45
43
|
*
|
|
46
|
-
* @
|
|
47
|
-
* @param {object} browsers - Browsers targeted.
|
|
44
|
+
* @deprecated since 2.1.0. Use getAllBrowsers instead.
|
|
48
45
|
* @param {object} options - Options.
|
|
49
|
-
* @param {
|
|
50
|
-
* @returns {
|
|
46
|
+
* @param {string} options.query - Browserslist query.
|
|
47
|
+
* @returns {object} Browsers mapped to minimum versions.
|
|
51
48
|
*/
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if ( ! Array.isArray( paths ) ) {
|
|
59
|
-
paths = [ paths ];
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (
|
|
63
|
-
options.builtins === false &&
|
|
64
|
-
paths.some( path => path.startsWith( 'javascript.builtins.' ) )
|
|
65
|
-
) {
|
|
66
|
-
return false;
|
|
67
|
-
}
|
|
68
|
-
if (
|
|
69
|
-
options.builtins === true &&
|
|
70
|
-
! paths.some( path => path.startsWith( 'javascript.builtins.' ) )
|
|
71
|
-
) {
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
path: for ( const path of paths ) {
|
|
76
|
-
let data = mdn;
|
|
77
|
-
for ( const k of path.split( '.' ) ) {
|
|
78
|
-
data = data[ k ];
|
|
79
|
-
if ( ! data ) {
|
|
80
|
-
warn( `Invalid feature map for rule ${ rule }: ${ path } does not exist` );
|
|
81
|
-
continue path;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
if ( ! data.__compat || ! data.__compat.support ) {
|
|
85
|
-
warn( `Invalid feature map for rule ${ rule }: No data at ${ path }` );
|
|
86
|
-
continue path;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
browser: for ( const browser of Object.keys( browsers ) ) {
|
|
90
|
-
if ( ! data.__compat.support[ browser ] ) {
|
|
91
|
-
debuglog( `No support data for ${ browser } for rule ${ rule } (${ path }), skipping` );
|
|
92
|
-
continue browser;
|
|
93
|
-
}
|
|
94
|
-
let support = data.__compat.support[ browser ];
|
|
95
|
-
if ( Array.isArray( support ) ) {
|
|
96
|
-
support = support[ 0 ];
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if ( support.version_added === null ) {
|
|
100
|
-
debuglog( `No support data for ${ browser } for rule ${ rule } (${ path }), skipping` );
|
|
101
|
-
continue browser;
|
|
102
|
-
} else if ( support.version_added === false ) {
|
|
103
|
-
debuglog( `${ browser } needs check for ${ rule } (${ path })` );
|
|
104
|
-
return true;
|
|
105
|
-
} else if ( support.version_added === true ) {
|
|
106
|
-
continue browser;
|
|
107
|
-
} else if ( semver.gt( semver.coerce( support.version_added ), browsers[ browser ] ) ) {
|
|
108
|
-
debuglog(
|
|
109
|
-
`${ browser } < ${ support.version_added } needs check for ${ rule } (${ path }); we have ${ browsers[ browser ] }`
|
|
110
|
-
);
|
|
111
|
-
return true;
|
|
112
|
-
} else if ( support.partial_implementation ) {
|
|
113
|
-
debuglog(
|
|
114
|
-
`${ browser } needs check for ${ rule } (${ path }) due to partial implementation`
|
|
115
|
-
);
|
|
116
|
-
return true;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
49
|
+
function getBrowsers( options = {} ) {
|
|
50
|
+
warn( 'getBrowsers is deprecated. Use getAllBrowsers instead.' );
|
|
51
|
+
const browsers = getAllBrowsers( options );
|
|
52
|
+
const ret = {};
|
|
53
|
+
for ( const k of Object.keys( browsers ) ) {
|
|
54
|
+
ret[ k ] = browsers[ k ][ 0 ];
|
|
119
55
|
}
|
|
120
|
-
|
|
121
|
-
return false;
|
|
56
|
+
return ret;
|
|
122
57
|
}
|
|
123
58
|
|
|
124
59
|
/**
|
|
@@ -130,7 +65,7 @@ function needsCheck( rule, browsers, options = {} ) {
|
|
|
130
65
|
* @returns {object} Rules configuration.
|
|
131
66
|
*/
|
|
132
67
|
function getRules( options = {} ) {
|
|
133
|
-
const browsers =
|
|
68
|
+
const browsers = getAllBrowsers( options );
|
|
134
69
|
const ret = {};
|
|
135
70
|
for ( const rule of Object.keys( esRules ) ) {
|
|
136
71
|
ret[ `es-x/${ rule }` ] = needsCheck( rule, browsers, options ) ? 2 : 0;
|
|
@@ -139,6 +74,7 @@ function getRules( options = {} ) {
|
|
|
139
74
|
}
|
|
140
75
|
|
|
141
76
|
module.exports = {
|
|
77
|
+
getAllBrowsers,
|
|
142
78
|
getBrowsers,
|
|
143
79
|
getRules,
|
|
144
80
|
};
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
const mdn = require( '@mdn/browser-compat-data' );
|
|
2
|
+
const debug = require( 'debug' );
|
|
3
|
+
const semver = require( 'semver' );
|
|
4
|
+
const rulesMap = require( './rulesMap.js' );
|
|
5
|
+
|
|
6
|
+
const warn = debug( '@automattic/eslint-config-target-es:warn' );
|
|
7
|
+
const debuglog = debug( '@automattic/eslint-config-target-es:debug' );
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Test if a rule needs to be checked.
|
|
11
|
+
*
|
|
12
|
+
* @param {string} rule - Rule.
|
|
13
|
+
* @param {object} browsers - Browsers targeted.
|
|
14
|
+
* @param {object} options - Options.
|
|
15
|
+
* @param {boolean|null} options.builtins - If true, only rules with "javascript.builtins" paths are checked. If false, such rules are not checked. If null/undefined, all may be checked.
|
|
16
|
+
* @returns {boolean} Whether the rule needs to be checked.
|
|
17
|
+
*/
|
|
18
|
+
function needsCheck( rule, browsers, options = {} ) {
|
|
19
|
+
let paths = rulesMap[ rule ];
|
|
20
|
+
if ( paths === true || paths === false ) {
|
|
21
|
+
return paths;
|
|
22
|
+
}
|
|
23
|
+
if ( paths === undefined ) {
|
|
24
|
+
warn( `No feature map for rule ${ rule }` );
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
if ( ! Array.isArray( paths ) ) {
|
|
28
|
+
paths = [ paths ];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (
|
|
32
|
+
options.builtins === false &&
|
|
33
|
+
paths.some( path => path.startsWith( 'javascript.builtins.' ) )
|
|
34
|
+
) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
if (
|
|
38
|
+
options.builtins === true &&
|
|
39
|
+
! paths.some( path => path.startsWith( 'javascript.builtins.' ) )
|
|
40
|
+
) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const semver000 = semver.coerce( '0.0.0' );
|
|
45
|
+
|
|
46
|
+
path: for ( const path of paths ) {
|
|
47
|
+
let data = mdn;
|
|
48
|
+
for ( const k of path.split( '.' ) ) {
|
|
49
|
+
data = data[ k ];
|
|
50
|
+
if ( ! data ) {
|
|
51
|
+
warn( `Invalid feature map for rule ${ rule }: ${ path } does not exist` );
|
|
52
|
+
continue path;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if ( ! data.__compat || ! data.__compat.support ) {
|
|
56
|
+
warn( `Invalid feature map for rule ${ rule }: No data at ${ path }` );
|
|
57
|
+
continue path;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
browser: for ( const browser of Object.keys( browsers ) ) {
|
|
61
|
+
if ( ! data.__compat.support[ browser ] ) {
|
|
62
|
+
warn( `No support data for ${ browser } for rule ${ rule } (${ path }), skipping` );
|
|
63
|
+
continue browser;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const supports = Array.isArray( data.__compat.support[ browser ] )
|
|
67
|
+
? data.__compat.support[ browser ]
|
|
68
|
+
: [ data.__compat.support[ browser ] ];
|
|
69
|
+
const vers = Array.isArray( browsers[ browser ] )
|
|
70
|
+
? browsers[ browser ]
|
|
71
|
+
: [ browsers[ browser ] ];
|
|
72
|
+
|
|
73
|
+
version: for ( const ver of vers ) {
|
|
74
|
+
const results = [];
|
|
75
|
+
support: for ( const support of supports ) {
|
|
76
|
+
if ( support.version_added === null ) {
|
|
77
|
+
continue support;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if ( support.version_added === false ) {
|
|
81
|
+
results.push( 'no support' );
|
|
82
|
+
continue support;
|
|
83
|
+
}
|
|
84
|
+
if ( support.version_added === 'preview' ) {
|
|
85
|
+
results.push( 'added version is "preview"' );
|
|
86
|
+
continue support;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
let added, removed;
|
|
90
|
+
if ( support.version_added === true ) {
|
|
91
|
+
added = semver000;
|
|
92
|
+
} else {
|
|
93
|
+
added = support.version_added.startsWith( '≤' )
|
|
94
|
+
? semver000
|
|
95
|
+
: semver.coerce( support.version_added );
|
|
96
|
+
}
|
|
97
|
+
if ( support.version_removed === true ) {
|
|
98
|
+
removed = semver000;
|
|
99
|
+
} else if (
|
|
100
|
+
typeof support.version_removed === 'string' &&
|
|
101
|
+
support.version_removed !== 'preview'
|
|
102
|
+
) {
|
|
103
|
+
removed = support.version_removed.startsWith( '≤' )
|
|
104
|
+
? semver000
|
|
105
|
+
: semver.coerce( support.version_removed );
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const range = removed ? `${ added } – <${ removed }` : `>= ${ added }`;
|
|
109
|
+
|
|
110
|
+
if ( semver.gt( added, ver ) || ( removed && semver.lte( removed, ver ) ) ) {
|
|
111
|
+
results.push( `outside range ${ range }` );
|
|
112
|
+
} else if ( support.partial_implementation ) {
|
|
113
|
+
results.push( `partial implementation for ${ range }` );
|
|
114
|
+
} else if ( support.prefix ) {
|
|
115
|
+
results.push( `prefixed implementation for ${ range }` );
|
|
116
|
+
} else if ( support.alternative_name ) {
|
|
117
|
+
results.push( `alternatively named implementation for ${ range }` );
|
|
118
|
+
} else if ( support.flags ) {
|
|
119
|
+
results.push( `flagged implementation for ${ range }` );
|
|
120
|
+
} else {
|
|
121
|
+
// It's good! Check the next version.
|
|
122
|
+
continue version;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// If there was no support data at all...
|
|
127
|
+
if ( results.length === 0 ) {
|
|
128
|
+
warn( `No support data for ${ browser } for rule ${ rule } (${ path }), skipping` );
|
|
129
|
+
continue browser;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// If no support entry hit the "It's good" case, it's no good. Log the reasons.
|
|
133
|
+
// If there are reasons other than "outside range", skip any "outside range" as irrelevant.
|
|
134
|
+
let results2 = results.filter( v => ! v.startsWith( 'outside range' ) );
|
|
135
|
+
if ( results2.length === 0 ) {
|
|
136
|
+
results2 = results;
|
|
137
|
+
}
|
|
138
|
+
debuglog(
|
|
139
|
+
`${ browser } ${ ver } needs check for ${ rule } (${ path }); ${ results2.join( '; ' ) }`
|
|
140
|
+
);
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
module.exports = {
|
|
150
|
+
needsCheck,
|
|
151
|
+
};
|
package/src/rulesMap.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
module.exports = {
|
|
4
4
|
// ?
|
|
5
5
|
'no-atomics-waitasync': 'javascript.builtins.Atomics.waitAsync',
|
|
6
|
+
'no-regexp-v-flag': 'javascript.builtins.RegExp.unicodeSets',
|
|
6
7
|
'no-string-prototype-iswellformed-towellformed': [
|
|
7
8
|
'javascript.builtins.String.isWellFormed',
|
|
8
9
|
'javascript.builtins.String.toWellFormed',
|