es-guard 1.0.0 → 1.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 +1 -1
- package/dist/cli.js +77 -10
- package/dist/lib/checkCompatiblity.js +12 -0
- package/dist/lib/detectTarget.js +244 -0
- package/package.json +11 -4
package/README.md
CHANGED
package/dist/cli.js
CHANGED
|
@@ -4,6 +4,8 @@ import * as fs from "fs";
|
|
|
4
4
|
import packageJson from "../package.json" with { type: "json" };
|
|
5
5
|
import { checkCompatibility } from "./lib/checkCompatiblity.js";
|
|
6
6
|
import { getBrowserTargetsFromString } from "./lib/getBrowserTargets.js";
|
|
7
|
+
import { detectTarget } from "./lib/detectTarget.js";
|
|
8
|
+
import path from "path";
|
|
7
9
|
const version = packageJson.version;
|
|
8
10
|
// Create the main program
|
|
9
11
|
const program = new Command();
|
|
@@ -13,18 +15,30 @@ program
|
|
|
13
15
|
.description("JavaScript Compatibility Checker - Check if your JavaScript code is compatible with target environments")
|
|
14
16
|
.version(version)
|
|
15
17
|
.argument("[directory]", "Directory to scan for JavaScript files", "dist")
|
|
16
|
-
.option("-t, --target <version>", "Target ES version (2015, 2016, 2017, etc. or 6, 7, 8, etc. or 'latest')
|
|
18
|
+
.option("-t, --target <version>", "Target ES version (2015, 2016, 2017, etc. or 6, 7, 8, etc. or 'latest'). If not specified, will auto-detect from project config files.")
|
|
17
19
|
.option("-b, --browsers <targets>", "Browser targets for compatibility checking (optional: auto-determined from target)")
|
|
18
20
|
.addHelpText("after", `
|
|
19
21
|
|
|
20
22
|
Examples:
|
|
21
|
-
es-guard # Check 'dist' directory with
|
|
22
|
-
es-guard build # Check 'build' directory with
|
|
23
|
+
es-guard # Check 'dist' directory with auto-detected target
|
|
24
|
+
es-guard build # Check 'build' directory with auto-detected target
|
|
23
25
|
es-guard -t 2020 build # Check 'build' directory with ES2020 (auto-determined browsers)
|
|
24
26
|
es-guard -t 6 build # Check 'build' directory with ES6 (auto-determined browsers)
|
|
25
27
|
es-guard -t latest build # Check 'build' directory with latest ES (auto-determined browsers)
|
|
26
28
|
es-guard --target 2017 --browsers "> 0.5%, last 2 versions" dist
|
|
27
29
|
|
|
30
|
+
Auto-detection searches for ES target in:
|
|
31
|
+
- package.json (browserslist field)
|
|
32
|
+
- tsconfig.json (compilerOptions.target)
|
|
33
|
+
- babel.config.js (.babelrc) (@babel/preset-env targets)
|
|
34
|
+
- vite.config.js/ts (esbuild target)
|
|
35
|
+
- webpack.config.js/ts (target)
|
|
36
|
+
|
|
37
|
+
Auto-detection behavior:
|
|
38
|
+
- Searches in the directory being scanned first
|
|
39
|
+
- Falls back to current working directory if no config found
|
|
40
|
+
- Uses the first valid target found (package.json has highest priority)
|
|
41
|
+
|
|
28
42
|
Browser targets use Browserslist format:
|
|
29
43
|
- If not specified, browsers will be auto-determined from the ES target version
|
|
30
44
|
- "> 1%, last 2 versions, not dead, ie 11" (for ES2015/ES6)
|
|
@@ -40,10 +54,12 @@ Exit codes:
|
|
|
40
54
|
program.hook("preAction", (thisCommand) => {
|
|
41
55
|
const options = thisCommand.opts();
|
|
42
56
|
const target = options.target;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
57
|
+
if (target) {
|
|
58
|
+
// Validate ES target format - accept year format (YYYY), numeric format (N), or "latest"
|
|
59
|
+
if (!/^\d{4}$/.test(target) && !/^\d+$/.test(target) && target !== "latest") {
|
|
60
|
+
console.error(`Error: Invalid ES target: "${target}". Expected format: YYYY (e.g., 2015, 2020), numeric (e.g., 6, 11), or "latest"`);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
47
63
|
}
|
|
48
64
|
});
|
|
49
65
|
// Main action
|
|
@@ -59,16 +75,67 @@ program.action(async (directory, options) => {
|
|
|
59
75
|
console.error(`Error: "${directory}" is not a directory`);
|
|
60
76
|
process.exit(1);
|
|
61
77
|
}
|
|
78
|
+
// Determine target - use provided target or auto-detect
|
|
79
|
+
let target = options.target;
|
|
80
|
+
let targetSource = "specified";
|
|
81
|
+
if (!target) {
|
|
82
|
+
// Try to detect target from current working directory
|
|
83
|
+
const detectedResult = detectTarget(process.cwd());
|
|
84
|
+
if (detectedResult) {
|
|
85
|
+
target = detectedResult.target;
|
|
86
|
+
targetSource = `auto-detected from ${detectedResult.source}`;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
console.error("Error: No target specified and could not auto-detect from project configuration files.");
|
|
90
|
+
console.error("Please specify a target with --target or ensure your project has a valid configuration file.");
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
62
94
|
// Determine browser targets
|
|
63
|
-
|
|
95
|
+
let browserTargets;
|
|
96
|
+
if (options.browsers) {
|
|
97
|
+
browserTargets = options.browsers;
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
// If auto-detected from package.json or browserslist file, check for ES version strings
|
|
101
|
+
if (targetSource.startsWith("auto-detected from ")) {
|
|
102
|
+
const configFile = targetSource.replace("auto-detected from ", "");
|
|
103
|
+
let browserslistEntries = [];
|
|
104
|
+
if (configFile === "package.json") {
|
|
105
|
+
const pkgPath = path.join(process.cwd(), "package.json");
|
|
106
|
+
if (fs.existsSync(pkgPath)) {
|
|
107
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
108
|
+
if (pkg.browserslist) {
|
|
109
|
+
browserslistEntries = Array.isArray(pkg.browserslist) ? pkg.browserslist : [pkg.browserslist];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
else if (configFile === ".browserslistrc" || configFile === ".browserslist") {
|
|
114
|
+
const blPath = path.join(process.cwd(), configFile);
|
|
115
|
+
if (fs.existsSync(blPath)) {
|
|
116
|
+
browserslistEntries = fs
|
|
117
|
+
.readFileSync(blPath, "utf-8")
|
|
118
|
+
.split(/\r?\n/)
|
|
119
|
+
.map((l) => l.trim())
|
|
120
|
+
.filter((l) => l && !l.startsWith("#"));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const esVersionRegex = /^es\d{1,4}$/i;
|
|
124
|
+
const invalidEntries = browserslistEntries.filter((entry) => esVersionRegex.test(entry));
|
|
125
|
+
if (invalidEntries.length > 0) {
|
|
126
|
+
console.warn(`Warning: Detected ES version string(s) in browserslist (${invalidEntries.join(", ")}). These are not valid Browserslist queries and will be ignored for browser compatibility checks.`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
browserTargets = getBrowserTargetsFromString(target);
|
|
130
|
+
}
|
|
64
131
|
console.log(`🔍 ES-Guard v${version}`);
|
|
65
132
|
console.log(`📁 Scanning directory: ${directory}`);
|
|
66
|
-
console.log(`🎯 Target ES version: ${
|
|
133
|
+
console.log(`🎯 Target ES version: ${target} (${targetSource})`);
|
|
67
134
|
console.log(`🌐 Browser targets: ${browserTargets}${options.browsers ? "" : " (auto-determined)"}`);
|
|
68
135
|
console.log("");
|
|
69
136
|
const violations = await checkCompatibility({
|
|
70
137
|
dir: directory,
|
|
71
|
-
target:
|
|
138
|
+
target: target,
|
|
72
139
|
browsers: browserTargets,
|
|
73
140
|
});
|
|
74
141
|
if (violations.length > 0) {
|
|
@@ -7,6 +7,11 @@ export const checkCompatibility = async (config) => {
|
|
|
7
7
|
console.log(`No JavaScript files found in directory: ${config.dir}`);
|
|
8
8
|
return [];
|
|
9
9
|
}
|
|
10
|
+
// Set BROWSERSLIST env variable to override Browserslist file detection
|
|
11
|
+
const originalBrowserslistEnv = process.env.BROWSERSLIST;
|
|
12
|
+
if (config.browsers) {
|
|
13
|
+
process.env.BROWSERSLIST = config.browsers;
|
|
14
|
+
}
|
|
10
15
|
const eslint = new ESLint(createESLintConfig(config.target, config.browsers));
|
|
11
16
|
const violations = [];
|
|
12
17
|
for (const file of jsFiles) {
|
|
@@ -30,5 +35,12 @@ export const checkCompatibility = async (config) => {
|
|
|
30
35
|
console.warn(`Warning: Could not lint file ${file}:`, error);
|
|
31
36
|
}
|
|
32
37
|
}
|
|
38
|
+
// Restore original BROWSERSLIST env variable
|
|
39
|
+
if (originalBrowserslistEnv !== undefined) {
|
|
40
|
+
process.env.BROWSERSLIST = originalBrowserslistEnv;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
delete process.env.BROWSERSLIST;
|
|
44
|
+
}
|
|
33
45
|
return violations;
|
|
34
46
|
};
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
// Shared utilities for ES version parsing and conversion
|
|
4
|
+
/**
|
|
5
|
+
* Parse ES version from string (e.g., "es6", "es2020", "ES2015")
|
|
6
|
+
* Returns the year as a string, or null if not found
|
|
7
|
+
*/
|
|
8
|
+
const parseESVersion = (str) => {
|
|
9
|
+
const esMatch = str.match(/es(\d+)/i);
|
|
10
|
+
if (esMatch) {
|
|
11
|
+
const esVersion = parseInt(esMatch[1]);
|
|
12
|
+
// If it's a 4-digit year (like 2020), use it directly
|
|
13
|
+
if (esVersion >= 2000) {
|
|
14
|
+
return esVersion.toString();
|
|
15
|
+
}
|
|
16
|
+
// Otherwise convert ES version to year: ES6=2015, ES7=2016, ES8=2017, etc.
|
|
17
|
+
return (2009 + esVersion).toString();
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Common target mapping for TypeScript, Vite, and Webpack configs
|
|
23
|
+
*/
|
|
24
|
+
const TARGET_MAP = {
|
|
25
|
+
// TypeScript targets
|
|
26
|
+
ES2022: "2022",
|
|
27
|
+
ES2021: "2021",
|
|
28
|
+
ES2020: "2020",
|
|
29
|
+
ES2019: "2019",
|
|
30
|
+
ES2018: "2018",
|
|
31
|
+
ES2017: "2017",
|
|
32
|
+
ES2016: "2016",
|
|
33
|
+
ES2015: "2015",
|
|
34
|
+
ES6: "2015",
|
|
35
|
+
ES5: "2009",
|
|
36
|
+
ES3: "1999",
|
|
37
|
+
// Vite/Webpack targets (lowercase)
|
|
38
|
+
es2022: "2022",
|
|
39
|
+
es2021: "2021",
|
|
40
|
+
es2020: "2020",
|
|
41
|
+
es2019: "2019",
|
|
42
|
+
es2018: "2018",
|
|
43
|
+
es2017: "2017",
|
|
44
|
+
es2016: "2016",
|
|
45
|
+
es2015: "2015",
|
|
46
|
+
es6: "2015",
|
|
47
|
+
es5: "2009",
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Helper to read and parse JSON file safely
|
|
51
|
+
*/
|
|
52
|
+
const readJsonFile = (filePath) => {
|
|
53
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
54
|
+
return JSON.parse(content);
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Type guard for package.json structure
|
|
58
|
+
*/
|
|
59
|
+
const isPackageJson = (obj) => {
|
|
60
|
+
return typeof obj === "object" && obj !== null && "browserslist" in obj;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Type guard for tsconfig.json structure
|
|
64
|
+
*/
|
|
65
|
+
const isTsConfig = (obj) => {
|
|
66
|
+
return typeof obj === "object" && obj !== null && "compilerOptions" in obj;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Type guard for .babelrc structure
|
|
70
|
+
*/
|
|
71
|
+
const isBabelRc = (obj) => {
|
|
72
|
+
return typeof obj === "object" && obj !== null && "presets" in obj;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Helper to read text file safely
|
|
76
|
+
*/
|
|
77
|
+
const readTextFile = (filePath) => {
|
|
78
|
+
return fs.readFileSync(filePath, "utf-8");
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Detects ES target from common frontend project configuration files.
|
|
82
|
+
* Searches in order of preference: package.json, .browserslistrc/.browserslist, tsconfig.json, babel.config.js, .babelrc, vite.config.js, webpack.config.js
|
|
83
|
+
* Returns an object with the detected target and the source file name, or null if not found
|
|
84
|
+
*/
|
|
85
|
+
export const detectTarget = (cwd = process.cwd()) => {
|
|
86
|
+
const configFiles = [
|
|
87
|
+
{ name: "package.json", parser: parsePackageJson },
|
|
88
|
+
{ name: ".browserslistrc", parser: parseBrowserslistFile },
|
|
89
|
+
{ name: ".browserslist", parser: parseBrowserslistFile },
|
|
90
|
+
{ name: "tsconfig.json", parser: parseTsConfig },
|
|
91
|
+
{ name: "babel.config.js", parser: parseBabelConfig },
|
|
92
|
+
{ name: ".babelrc", parser: parseBabelRc },
|
|
93
|
+
{ name: "vite.config.js", parser: parseViteConfig },
|
|
94
|
+
{ name: "vite.config.ts", parser: parseViteConfig },
|
|
95
|
+
{ name: "webpack.config.js", parser: parseWebpackConfig },
|
|
96
|
+
{ name: "webpack.config.ts", parser: parseWebpackConfig },
|
|
97
|
+
];
|
|
98
|
+
for (const config of configFiles) {
|
|
99
|
+
const filePath = path.join(cwd, config.name);
|
|
100
|
+
if (fs.existsSync(filePath)) {
|
|
101
|
+
try {
|
|
102
|
+
const target = config.parser(filePath);
|
|
103
|
+
if (target) {
|
|
104
|
+
return { target, source: config.name };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
console.warn(`Error parsing ${config.name}:`, error);
|
|
109
|
+
// Continue to next config file if parsing fails
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return null;
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Parse package.json for ES target in browserslist
|
|
118
|
+
*/
|
|
119
|
+
const parsePackageJson = (filePath) => {
|
|
120
|
+
const pkg = readJsonFile(filePath);
|
|
121
|
+
if (!isPackageJson(pkg)) {
|
|
122
|
+
console.warn(`Warning: ${filePath} does not look like a valid package.json (missing or invalid browserslist field).`);
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
// Check for browserslist field
|
|
126
|
+
if (pkg.browserslist) {
|
|
127
|
+
const browserslist = Array.isArray(pkg.browserslist) ? pkg.browserslist : [pkg.browserslist];
|
|
128
|
+
// Look for ES target in browserslist
|
|
129
|
+
for (const browser of browserslist) {
|
|
130
|
+
if (typeof browser === "string") {
|
|
131
|
+
const target = parseESVersion(browser);
|
|
132
|
+
if (target) {
|
|
133
|
+
return target;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Note: engines.node is for development/build tools, not client-side targets
|
|
139
|
+
// So we don't use it for auto-detection
|
|
140
|
+
return null;
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Parse tsconfig.json for target
|
|
144
|
+
*/
|
|
145
|
+
const parseTsConfig = (filePath) => {
|
|
146
|
+
const config = readJsonFile(filePath);
|
|
147
|
+
if (!isTsConfig(config)) {
|
|
148
|
+
console.warn(`Warning: ${filePath} does not look like a valid tsconfig.json (missing or invalid compilerOptions field).`);
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
if (config.compilerOptions?.target) {
|
|
152
|
+
const target = config.compilerOptions.target;
|
|
153
|
+
return TARGET_MAP[target] || null;
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* Parse babel.config.js for preset-env target
|
|
159
|
+
*/
|
|
160
|
+
const parseBabelConfig = (filePath) => {
|
|
161
|
+
const content = readTextFile(filePath);
|
|
162
|
+
// Look for @babel/preset-env configuration
|
|
163
|
+
const presetEnvMatch = content.match(/@babel\/preset-env.*?targets.*?(\{[^}]*\})/s);
|
|
164
|
+
if (presetEnvMatch) {
|
|
165
|
+
const targetsStr = presetEnvMatch[1];
|
|
166
|
+
// Look for browsers or esmodules target
|
|
167
|
+
const browsersMatch = targetsStr.match(/browsers.*?\[(.*?)\]/);
|
|
168
|
+
if (browsersMatch) {
|
|
169
|
+
const browsers = browsersMatch[1];
|
|
170
|
+
return parseESVersion(browsers);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return null;
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* Parse .babelrc for preset-env target
|
|
177
|
+
*/
|
|
178
|
+
const parseBabelRc = (filePath) => {
|
|
179
|
+
const config = readJsonFile(filePath);
|
|
180
|
+
if (!isBabelRc(config)) {
|
|
181
|
+
console.warn(`Warning: ${filePath} does not look like a valid .babelrc (missing or invalid presets field).`);
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
if (config.presets) {
|
|
185
|
+
for (const preset of config.presets) {
|
|
186
|
+
if (Array.isArray(preset) && preset[0] === "@babel/preset-env") {
|
|
187
|
+
const options = preset[1];
|
|
188
|
+
if (options?.targets?.browsers) {
|
|
189
|
+
const browsers = options.targets.browsers;
|
|
190
|
+
for (const browser of browsers) {
|
|
191
|
+
const target = parseESVersion(browser);
|
|
192
|
+
if (target) {
|
|
193
|
+
return target;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return null;
|
|
201
|
+
};
|
|
202
|
+
/**
|
|
203
|
+
* Parse vite.config.js/ts for target
|
|
204
|
+
*/
|
|
205
|
+
const parseViteConfig = (filePath) => {
|
|
206
|
+
const content = readTextFile(filePath);
|
|
207
|
+
// Look for esbuild target - more flexible pattern
|
|
208
|
+
const esbuildMatch = content.match(/esbuild\s*:\s*\{[^}]*target\s*:\s*['"`]([^'"`]+)['"`]/s);
|
|
209
|
+
if (esbuildMatch) {
|
|
210
|
+
const target = esbuildMatch[1];
|
|
211
|
+
return TARGET_MAP[target] || null;
|
|
212
|
+
}
|
|
213
|
+
return null;
|
|
214
|
+
};
|
|
215
|
+
/**
|
|
216
|
+
* Parse webpack.config.js/ts for target
|
|
217
|
+
*/
|
|
218
|
+
const parseWebpackConfig = (filePath) => {
|
|
219
|
+
const content = readTextFile(filePath);
|
|
220
|
+
// Look for target configuration
|
|
221
|
+
const targetMatch = content.match(/target.*?['"`]([^'"`]+)['"`]/);
|
|
222
|
+
if (targetMatch) {
|
|
223
|
+
const target = targetMatch[1];
|
|
224
|
+
return TARGET_MAP[target] || null;
|
|
225
|
+
}
|
|
226
|
+
return null;
|
|
227
|
+
};
|
|
228
|
+
/**
|
|
229
|
+
* Parse .browserslistrc or .browserslist file for ES target
|
|
230
|
+
*/
|
|
231
|
+
const parseBrowserslistFile = (filePath) => {
|
|
232
|
+
const content = readTextFile(filePath);
|
|
233
|
+
const lines = content
|
|
234
|
+
.split(/\r?\n/)
|
|
235
|
+
.map((line) => line.trim())
|
|
236
|
+
.filter((line) => line && !line.startsWith("#"));
|
|
237
|
+
for (const browser of lines) {
|
|
238
|
+
const target = parseESVersion(browser);
|
|
239
|
+
if (target) {
|
|
240
|
+
return target;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return null;
|
|
244
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "es-guard",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "A tool to check JavaScript compatibility with target environments",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/cli.js",
|
|
@@ -14,8 +14,10 @@
|
|
|
14
14
|
"build": "tsc",
|
|
15
15
|
"dev": "tsc --watch",
|
|
16
16
|
"start": "node dist/cli.js",
|
|
17
|
-
"test": "npm run build && vitest",
|
|
18
|
-
"test
|
|
17
|
+
"test:dev": "npm run build && vitest",
|
|
18
|
+
"test": "npm run build && vitest run",
|
|
19
|
+
"test:junit": "npm run build && vitest run --reporter=junit --outputFile=test-report.junit.xml",
|
|
20
|
+
"test:junit:coverage": "npm run build && vitest run --reporter=junit --outputFile=test-report.junit.xml --coverage",
|
|
19
21
|
"coverage": "vitest run --coverage",
|
|
20
22
|
"coverage:check": "vitest run --coverage --reporter=verbose",
|
|
21
23
|
"lint": "eslint src/**/*.ts",
|
|
@@ -72,5 +74,10 @@
|
|
|
72
74
|
"url": "https://github.com/mkayander/es-guard/issues"
|
|
73
75
|
},
|
|
74
76
|
"homepage": "https://github.com/mkayander/es-guard#readme",
|
|
75
|
-
"packageManager": "pnpm@10.12.4+sha512.5ea8b0deed94ed68691c9bad4c955492705c5eeb8a87ef86bc62c74a26b037b08ff9570f108b2e4dbd1dd1a9186fea925e527f141c648e85af45631074680184"
|
|
77
|
+
"packageManager": "pnpm@10.12.4+sha512.5ea8b0deed94ed68691c9bad4c955492705c5eeb8a87ef86bc62c74a26b037b08ff9570f108b2e4dbd1dd1a9186fea925e527f141c648e85af45631074680184",
|
|
78
|
+
"browserslist": [
|
|
79
|
+
"es2020",
|
|
80
|
+
"> 1%",
|
|
81
|
+
"last 2 versions"
|
|
82
|
+
]
|
|
76
83
|
}
|