eslint-plugin-baseline-js 0.1.0 → 0.2.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/README.md +3 -2
- package/dist/index.cjs +33 -19
- package/dist/index.d.cts +6 -13
- package/dist/index.d.mts +6 -13
- package/dist/index.mjs +33 -19
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
Enforce the JavaScript Baseline (`widely` / `newly` / `year`) with a single ESLint rule powered by web‑features.
|
|
8
8
|
This plugin delegates detection to eslint-plugin-es-x and ESLint core (plus a few small gap‑filling rules) and reports with one consistent Baseline message.
|
|
9
9
|
|
|
10
|
+
[](https://www.npmjs.com/package/eslint-plugin-baseline-js)
|
|
10
11
|
[](https://github.com/3ru/eslint-plugin-baseline-js/actions/workflows/ci.yml)
|
|
11
12
|
[](https://github.com/3ru/eslint-plugin-baseline-js/actions/workflows/release.yml)
|
|
12
13
|
<img alt="License" src="https://img.shields.io/badge/license-MIT-blue" />
|
|
@@ -56,11 +57,11 @@ export default [
|
|
|
56
57
|
|
|
57
58
|
// Recommended: enables Web APIs & JS builtins detection with `preset: 'auto'`.
|
|
58
59
|
// Level defaults to 'error'; pass level to change severity
|
|
59
|
-
|
|
60
|
+
baselineJs.configs.recommended({ available: "widely", level: "warn" }),
|
|
60
61
|
|
|
61
62
|
// TypeScript-aware: requires type info for instance-member checks (`preset: 'type-aware'`).
|
|
62
63
|
// Works best with @typescript-eslint/parser and a proper tsconfig.
|
|
63
|
-
//
|
|
64
|
+
// baselineJs.configs["recommended-ts"]({ available: "widely", level: "error" }),
|
|
64
65
|
];
|
|
65
66
|
```
|
|
66
67
|
|
package/dist/index.cjs
CHANGED
|
@@ -28,11 +28,6 @@ let eslint_plugin_es_x = require("eslint-plugin-es-x");
|
|
|
28
28
|
eslint_plugin_es_x = __toESM(eslint_plugin_es_x);
|
|
29
29
|
|
|
30
30
|
//#region src/configs/baseline.ts
|
|
31
|
-
function baselineConfigs(opts = {}) {
|
|
32
|
-
const available = opts.available ?? opts.baseline ?? "widely";
|
|
33
|
-
const level = opts.level ?? "error";
|
|
34
|
-
return [{ rules: { "baseline-js/use-baseline": [level, { available }] } }];
|
|
35
|
-
}
|
|
36
31
|
/**
|
|
37
32
|
* Recommended config: enable Baseline with Web APIs and JS builtins detection on auto preset.
|
|
38
33
|
* - baseline: defaults to 'widely'
|
|
@@ -41,11 +36,14 @@ function baselineConfigs(opts = {}) {
|
|
|
41
36
|
function recommendedConfig(opts = {}) {
|
|
42
37
|
const available = opts.available ?? opts.baseline ?? "widely";
|
|
43
38
|
const level = opts.level ?? "error";
|
|
44
|
-
return
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
39
|
+
return {
|
|
40
|
+
files: ["**/*.{js,cjs,mjs,jsx}"],
|
|
41
|
+
rules: { "baseline-js/use-baseline": [level, {
|
|
42
|
+
available,
|
|
43
|
+
includeWebApis: { preset: "auto" },
|
|
44
|
+
includeJsBuiltins: { preset: "auto" }
|
|
45
|
+
}] }
|
|
46
|
+
};
|
|
49
47
|
}
|
|
50
48
|
/**
|
|
51
49
|
* Recommended config for TypeScript-aware projects:
|
|
@@ -55,11 +53,14 @@ function recommendedConfig(opts = {}) {
|
|
|
55
53
|
function recommendedTsConfig(opts = {}) {
|
|
56
54
|
const available = opts.available ?? opts.baseline ?? "widely";
|
|
57
55
|
const level = opts.level ?? "error";
|
|
58
|
-
return
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
56
|
+
return {
|
|
57
|
+
files: ["**/*.{ts,tsx}"],
|
|
58
|
+
rules: { "baseline-js/use-baseline": [level, {
|
|
59
|
+
available,
|
|
60
|
+
includeWebApis: { preset: "type-aware" },
|
|
61
|
+
includeJsBuiltins: { preset: "type-aware" }
|
|
62
|
+
}] }
|
|
63
|
+
};
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
//#endregion
|
|
@@ -55813,6 +55814,7 @@ function isBeyondBaseline(featureId, baseline) {
|
|
|
55813
55814
|
if (baseline === "widely") return bucket !== "widely";
|
|
55814
55815
|
if (baseline === "newly") return bucket === "limited";
|
|
55815
55816
|
if (typeof baseline === "number") {
|
|
55817
|
+
if (bucket === "limited") return true;
|
|
55816
55818
|
const y = yearFrom(rec.status?.baseline_low_date) ?? yearFrom(rec.status?.baseline_high_date);
|
|
55817
55819
|
if (y == null) return false;
|
|
55818
55820
|
return y > baseline;
|
|
@@ -56201,6 +56203,8 @@ const rule$2 = {
|
|
|
56201
56203
|
},
|
|
56202
56204
|
MemberExpression(node) {
|
|
56203
56205
|
const m = node;
|
|
56206
|
+
const parent = m.parent;
|
|
56207
|
+
if (parent?.type === "CallExpression" && parent.callee === node) return;
|
|
56204
56208
|
if (m.computed === false && m.object?.type === "Identifier" && m.object?.name === "Math" && m.property?.type === "Identifier" && m.property?.name === "sumPrecise") report(m.property);
|
|
56205
56209
|
}
|
|
56206
56210
|
};
|
|
@@ -56259,11 +56263,14 @@ function mergeListeners(target, add) {
|
|
|
56259
56263
|
}
|
|
56260
56264
|
}
|
|
56261
56265
|
function baselineMessage(featureId, baseline) {
|
|
56262
|
-
if (baseline === "widely") return `Feature '${featureId}' is not a widely available Baseline feature.`;
|
|
56263
|
-
if (baseline === "newly") return `Feature '${featureId}' is not a newly available Baseline feature.`;
|
|
56264
56266
|
const rec = getFeatureRecord(featureId);
|
|
56267
|
+
const label = rec?.name || featureId;
|
|
56268
|
+
const idSuffix = rec?.name ? ` (${featureId})` : "";
|
|
56269
|
+
if (baseline === "widely") return `Feature '${label}'${idSuffix} is not a widely available Baseline feature.`;
|
|
56270
|
+
if (baseline === "newly") return `Feature '${label}'${idSuffix} is not a newly available Baseline feature.`;
|
|
56271
|
+
if (rec?.status?.baseline === false) return `Feature '${label}'${idSuffix} has Limited availability and exceeds ${baseline}.`;
|
|
56265
56272
|
const year = rec?.status?.baseline_low_date?.slice(0, 4) || rec?.status?.baseline_high_date?.slice(0, 4) || "unknown";
|
|
56266
|
-
return `Feature '${
|
|
56273
|
+
return `Feature '${label}'${idSuffix} became Baseline in ${year} and exceeds ${baseline}.`;
|
|
56267
56274
|
}
|
|
56268
56275
|
const rule = {
|
|
56269
56276
|
meta: {
|
|
@@ -56353,6 +56360,14 @@ const rule = {
|
|
|
56353
56360
|
}]
|
|
56354
56361
|
},
|
|
56355
56362
|
create(ctx) {
|
|
56363
|
+
const getFilename = ctx.getFilename;
|
|
56364
|
+
let filename = null;
|
|
56365
|
+
if (typeof getFilename === "function") try {
|
|
56366
|
+
filename = getFilename();
|
|
56367
|
+
} catch {}
|
|
56368
|
+
if (filename) {
|
|
56369
|
+
if (!/\.(?:[mc]?[jt]s|[jt]sx)$/i.test(filename)) return {};
|
|
56370
|
+
}
|
|
56356
56371
|
const opt = ctx.options[0] ?? {};
|
|
56357
56372
|
const baseline = getBaselineValue(opt);
|
|
56358
56373
|
const ignoreFeaturePatterns = opt.ignoreFeatures ?? [];
|
|
@@ -56548,7 +56563,6 @@ const rules = {
|
|
|
56548
56563
|
var src_default = {
|
|
56549
56564
|
rules,
|
|
56550
56565
|
configs: {
|
|
56551
|
-
baseline: baselineConfigs,
|
|
56552
56566
|
recommended: recommendedConfig,
|
|
56553
56567
|
"recommended-ts": recommendedTsConfig
|
|
56554
56568
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -16,14 +16,6 @@ type BaselineName = (typeof BASELINE)[keyof typeof BASELINE];
|
|
|
16
16
|
type BaselineOption = BaselineName | number;
|
|
17
17
|
//#endregion
|
|
18
18
|
//#region src/configs/baseline.d.ts
|
|
19
|
-
declare function baselineConfigs(opts?: {
|
|
20
|
-
available?: BaselineOption;
|
|
21
|
-
baseline?: BaselineOption;
|
|
22
|
-
env?: "browser" | "worker" | "node";
|
|
23
|
-
level?: "error" | "warn";
|
|
24
|
-
}): {
|
|
25
|
-
rules: Record<string, unknown>;
|
|
26
|
-
}[];
|
|
27
19
|
/**
|
|
28
20
|
* Recommended config: enable Baseline with Web APIs and JS builtins detection on auto preset.
|
|
29
21
|
* - baseline: defaults to 'widely'
|
|
@@ -35,8 +27,9 @@ declare function recommendedConfig(opts?: {
|
|
|
35
27
|
env?: "browser" | "worker" | "node";
|
|
36
28
|
level?: "error" | "warn";
|
|
37
29
|
}): {
|
|
38
|
-
|
|
39
|
-
|
|
30
|
+
readonly files: readonly ["**/*.{js,cjs,mjs,jsx}"];
|
|
31
|
+
readonly rules: Record<string, unknown>;
|
|
32
|
+
};
|
|
40
33
|
/**
|
|
41
34
|
* Recommended config for TypeScript-aware projects:
|
|
42
35
|
* - Uses 'type-aware' preset to require type information for instance-member checks.
|
|
@@ -48,14 +41,14 @@ declare function recommendedTsConfig(opts?: {
|
|
|
48
41
|
env?: "browser" | "worker" | "node";
|
|
49
42
|
level?: "error" | "warn";
|
|
50
43
|
}): {
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
readonly files: readonly ["**/*.{ts,tsx}"];
|
|
45
|
+
readonly rules: Record<string, unknown>;
|
|
46
|
+
};
|
|
53
47
|
//#endregion
|
|
54
48
|
//#region src/index.d.ts
|
|
55
49
|
declare const _default: {
|
|
56
50
|
readonly rules: Record<string, Rule.RuleModule>;
|
|
57
51
|
readonly configs: {
|
|
58
|
-
readonly baseline: typeof baselineConfigs;
|
|
59
52
|
readonly recommended: typeof recommendedConfig;
|
|
60
53
|
readonly "recommended-ts": typeof recommendedTsConfig;
|
|
61
54
|
};
|
package/dist/index.d.mts
CHANGED
|
@@ -16,14 +16,6 @@ type BaselineName = (typeof BASELINE)[keyof typeof BASELINE];
|
|
|
16
16
|
type BaselineOption = BaselineName | number;
|
|
17
17
|
//#endregion
|
|
18
18
|
//#region src/configs/baseline.d.ts
|
|
19
|
-
declare function baselineConfigs(opts?: {
|
|
20
|
-
available?: BaselineOption;
|
|
21
|
-
baseline?: BaselineOption;
|
|
22
|
-
env?: "browser" | "worker" | "node";
|
|
23
|
-
level?: "error" | "warn";
|
|
24
|
-
}): {
|
|
25
|
-
rules: Record<string, unknown>;
|
|
26
|
-
}[];
|
|
27
19
|
/**
|
|
28
20
|
* Recommended config: enable Baseline with Web APIs and JS builtins detection on auto preset.
|
|
29
21
|
* - baseline: defaults to 'widely'
|
|
@@ -35,8 +27,9 @@ declare function recommendedConfig(opts?: {
|
|
|
35
27
|
env?: "browser" | "worker" | "node";
|
|
36
28
|
level?: "error" | "warn";
|
|
37
29
|
}): {
|
|
38
|
-
|
|
39
|
-
|
|
30
|
+
readonly files: readonly ["**/*.{js,cjs,mjs,jsx}"];
|
|
31
|
+
readonly rules: Record<string, unknown>;
|
|
32
|
+
};
|
|
40
33
|
/**
|
|
41
34
|
* Recommended config for TypeScript-aware projects:
|
|
42
35
|
* - Uses 'type-aware' preset to require type information for instance-member checks.
|
|
@@ -48,14 +41,14 @@ declare function recommendedTsConfig(opts?: {
|
|
|
48
41
|
env?: "browser" | "worker" | "node";
|
|
49
42
|
level?: "error" | "warn";
|
|
50
43
|
}): {
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
readonly files: readonly ["**/*.{ts,tsx}"];
|
|
45
|
+
readonly rules: Record<string, unknown>;
|
|
46
|
+
};
|
|
53
47
|
//#endregion
|
|
54
48
|
//#region src/index.d.ts
|
|
55
49
|
declare const _default: {
|
|
56
50
|
readonly rules: Record<string, Rule.RuleModule>;
|
|
57
51
|
readonly configs: {
|
|
58
|
-
readonly baseline: typeof baselineConfigs;
|
|
59
52
|
readonly recommended: typeof recommendedConfig;
|
|
60
53
|
readonly "recommended-ts": typeof recommendedTsConfig;
|
|
61
54
|
};
|
package/dist/index.mjs
CHANGED
|
@@ -2,11 +2,6 @@ import { builtinRules } from "eslint/use-at-your-own-risk";
|
|
|
2
2
|
import esx from "eslint-plugin-es-x";
|
|
3
3
|
|
|
4
4
|
//#region src/configs/baseline.ts
|
|
5
|
-
function baselineConfigs(opts = {}) {
|
|
6
|
-
const available = opts.available ?? opts.baseline ?? "widely";
|
|
7
|
-
const level = opts.level ?? "error";
|
|
8
|
-
return [{ rules: { "baseline-js/use-baseline": [level, { available }] } }];
|
|
9
|
-
}
|
|
10
5
|
/**
|
|
11
6
|
* Recommended config: enable Baseline with Web APIs and JS builtins detection on auto preset.
|
|
12
7
|
* - baseline: defaults to 'widely'
|
|
@@ -15,11 +10,14 @@ function baselineConfigs(opts = {}) {
|
|
|
15
10
|
function recommendedConfig(opts = {}) {
|
|
16
11
|
const available = opts.available ?? opts.baseline ?? "widely";
|
|
17
12
|
const level = opts.level ?? "error";
|
|
18
|
-
return
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
13
|
+
return {
|
|
14
|
+
files: ["**/*.{js,cjs,mjs,jsx}"],
|
|
15
|
+
rules: { "baseline-js/use-baseline": [level, {
|
|
16
|
+
available,
|
|
17
|
+
includeWebApis: { preset: "auto" },
|
|
18
|
+
includeJsBuiltins: { preset: "auto" }
|
|
19
|
+
}] }
|
|
20
|
+
};
|
|
23
21
|
}
|
|
24
22
|
/**
|
|
25
23
|
* Recommended config for TypeScript-aware projects:
|
|
@@ -29,11 +27,14 @@ function recommendedConfig(opts = {}) {
|
|
|
29
27
|
function recommendedTsConfig(opts = {}) {
|
|
30
28
|
const available = opts.available ?? opts.baseline ?? "widely";
|
|
31
29
|
const level = opts.level ?? "error";
|
|
32
|
-
return
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
return {
|
|
31
|
+
files: ["**/*.{ts,tsx}"],
|
|
32
|
+
rules: { "baseline-js/use-baseline": [level, {
|
|
33
|
+
available,
|
|
34
|
+
includeWebApis: { preset: "type-aware" },
|
|
35
|
+
includeJsBuiltins: { preset: "type-aware" }
|
|
36
|
+
}] }
|
|
37
|
+
};
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
//#endregion
|
|
@@ -55787,6 +55788,7 @@ function isBeyondBaseline(featureId, baseline) {
|
|
|
55787
55788
|
if (baseline === "widely") return bucket !== "widely";
|
|
55788
55789
|
if (baseline === "newly") return bucket === "limited";
|
|
55789
55790
|
if (typeof baseline === "number") {
|
|
55791
|
+
if (bucket === "limited") return true;
|
|
55790
55792
|
const y = yearFrom(rec.status?.baseline_low_date) ?? yearFrom(rec.status?.baseline_high_date);
|
|
55791
55793
|
if (y == null) return false;
|
|
55792
55794
|
return y > baseline;
|
|
@@ -56175,6 +56177,8 @@ const rule$2 = {
|
|
|
56175
56177
|
},
|
|
56176
56178
|
MemberExpression(node) {
|
|
56177
56179
|
const m = node;
|
|
56180
|
+
const parent = m.parent;
|
|
56181
|
+
if (parent?.type === "CallExpression" && parent.callee === node) return;
|
|
56178
56182
|
if (m.computed === false && m.object?.type === "Identifier" && m.object?.name === "Math" && m.property?.type === "Identifier" && m.property?.name === "sumPrecise") report(m.property);
|
|
56179
56183
|
}
|
|
56180
56184
|
};
|
|
@@ -56233,11 +56237,14 @@ function mergeListeners(target, add) {
|
|
|
56233
56237
|
}
|
|
56234
56238
|
}
|
|
56235
56239
|
function baselineMessage(featureId, baseline) {
|
|
56236
|
-
if (baseline === "widely") return `Feature '${featureId}' is not a widely available Baseline feature.`;
|
|
56237
|
-
if (baseline === "newly") return `Feature '${featureId}' is not a newly available Baseline feature.`;
|
|
56238
56240
|
const rec = getFeatureRecord(featureId);
|
|
56241
|
+
const label = rec?.name || featureId;
|
|
56242
|
+
const idSuffix = rec?.name ? ` (${featureId})` : "";
|
|
56243
|
+
if (baseline === "widely") return `Feature '${label}'${idSuffix} is not a widely available Baseline feature.`;
|
|
56244
|
+
if (baseline === "newly") return `Feature '${label}'${idSuffix} is not a newly available Baseline feature.`;
|
|
56245
|
+
if (rec?.status?.baseline === false) return `Feature '${label}'${idSuffix} has Limited availability and exceeds ${baseline}.`;
|
|
56239
56246
|
const year = rec?.status?.baseline_low_date?.slice(0, 4) || rec?.status?.baseline_high_date?.slice(0, 4) || "unknown";
|
|
56240
|
-
return `Feature '${
|
|
56247
|
+
return `Feature '${label}'${idSuffix} became Baseline in ${year} and exceeds ${baseline}.`;
|
|
56241
56248
|
}
|
|
56242
56249
|
const rule = {
|
|
56243
56250
|
meta: {
|
|
@@ -56327,6 +56334,14 @@ const rule = {
|
|
|
56327
56334
|
}]
|
|
56328
56335
|
},
|
|
56329
56336
|
create(ctx) {
|
|
56337
|
+
const getFilename = ctx.getFilename;
|
|
56338
|
+
let filename = null;
|
|
56339
|
+
if (typeof getFilename === "function") try {
|
|
56340
|
+
filename = getFilename();
|
|
56341
|
+
} catch {}
|
|
56342
|
+
if (filename) {
|
|
56343
|
+
if (!/\.(?:[mc]?[jt]s|[jt]sx)$/i.test(filename)) return {};
|
|
56344
|
+
}
|
|
56330
56345
|
const opt = ctx.options[0] ?? {};
|
|
56331
56346
|
const baseline = getBaselineValue(opt);
|
|
56332
56347
|
const ignoreFeaturePatterns = opt.ignoreFeatures ?? [];
|
|
@@ -56522,7 +56537,6 @@ const rules = {
|
|
|
56522
56537
|
var src_default = {
|
|
56523
56538
|
rules,
|
|
56524
56539
|
configs: {
|
|
56525
|
-
baseline: baselineConfigs,
|
|
56526
56540
|
recommended: recommendedConfig,
|
|
56527
56541
|
"recommended-ts": recommendedTsConfig
|
|
56528
56542
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-baseline-js",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Enforce JavaScript Baseline (widely/newly/year) browser compatibility with a single ESLint rule. Prevent runtime errors by catching unsupported JavaScript features during development.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -42,14 +42,14 @@
|
|
|
42
42
|
"eslint-plugin-es-x": "^9.1.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@biomejs/biome": "^2.2.
|
|
45
|
+
"@biomejs/biome": "^2.2.4",
|
|
46
46
|
"@semantic-release/changelog": "^6.0.3",
|
|
47
47
|
"@semantic-release/git": "^10.0.1",
|
|
48
48
|
"@types/eslint": "^9.6.1",
|
|
49
|
-
"@types/node": "^24.
|
|
49
|
+
"@types/node": "^24.4.0",
|
|
50
50
|
"@typescript-eslint/parser": "^8.43.0",
|
|
51
51
|
"semantic-release": "^24.2.7",
|
|
52
|
-
"tsdown": "v0.
|
|
52
|
+
"tsdown": "v0.15.1",
|
|
53
53
|
"typescript": "^5.4.0",
|
|
54
54
|
"vitest": "^3.2.4",
|
|
55
55
|
"web-features": "^2.47.0"
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"typescript",
|
|
76
76
|
"linting"
|
|
77
77
|
],
|
|
78
|
-
"homepage": "https://
|
|
78
|
+
"homepage": "https://baselinejs.vercel.app/",
|
|
79
79
|
"bugs": {
|
|
80
80
|
"url": "https://github.com/3ru/eslint-plugin-baseline-js/issues"
|
|
81
81
|
},
|