es-guard 1.2.0 → 1.3.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 +28 -28
- package/dist/lib/detectTarget.js +234 -54
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://codecov.io/gh/mkayander/es-guard)
|
|
4
4
|
|
|
5
|
-
A TypeScript-based tool
|
|
5
|
+
A powerful TypeScript-based tool that ensures your JavaScript code is compatible with target environments using ESLint.
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
- 🔍 **ES Version
|
|
10
|
-
- 🌐 **Browser
|
|
11
|
-
- 🎯 **
|
|
12
|
-
- 📁 **Directory Scanning**:
|
|
13
|
-
-
|
|
14
|
-
- 📦 **
|
|
9
|
+
- 🔍 **ES Version Validation**: Verify your JavaScript code compatibility with specific ES versions (ES2015, ES2016, ES2017, and beyond)
|
|
10
|
+
- 🌐 **Browser Support Verification**: Validate browser compatibility using eslint-plugin-compat
|
|
11
|
+
- 🎯 **Smart Browser Detection**: Automatically determine browser targets from ES version (optional)
|
|
12
|
+
- 📁 **Comprehensive Directory Scanning**: Effortlessly scan directories for JavaScript files
|
|
13
|
+
- 🚀 **GitHub Actions Integration**: Seamlessly integrate with GitHub Actions workflows
|
|
14
|
+
- 📦 **Flexible Installation**: Install globally or use as a project dependency
|
|
15
15
|
|
|
16
16
|
## Installation
|
|
17
17
|
|
|
@@ -38,13 +38,13 @@ npm run build
|
|
|
38
38
|
|
|
39
39
|
## Usage
|
|
40
40
|
|
|
41
|
-
### Command Line
|
|
41
|
+
### Command Line Interface
|
|
42
42
|
|
|
43
43
|
```bash
|
|
44
|
-
# Basic usage with
|
|
44
|
+
# Basic usage with auto-detected browsers
|
|
45
45
|
es-guard
|
|
46
46
|
|
|
47
|
-
#
|
|
47
|
+
# Validate specific directory
|
|
48
48
|
es-guard build
|
|
49
49
|
|
|
50
50
|
# Specify target ES version (year format)
|
|
@@ -59,10 +59,10 @@ es-guard -t latest build
|
|
|
59
59
|
# Specify custom browser targets
|
|
60
60
|
es-guard --browsers "> 0.5%, last 2 versions, Firefox ESR, not dead" dist
|
|
61
61
|
|
|
62
|
-
#
|
|
62
|
+
# Display help information
|
|
63
63
|
es-guard --help
|
|
64
64
|
|
|
65
|
-
# Show version
|
|
65
|
+
# Show version information
|
|
66
66
|
es-guard --version
|
|
67
67
|
```
|
|
68
68
|
|
|
@@ -71,13 +71,13 @@ es-guard --version
|
|
|
71
71
|
```typescript
|
|
72
72
|
import { checkCompatibility } from "es-guard";
|
|
73
73
|
|
|
74
|
-
// With auto-
|
|
74
|
+
// With auto-detected browsers
|
|
75
75
|
const violations = await checkCompatibility({
|
|
76
76
|
dir: "dist",
|
|
77
77
|
target: "2015",
|
|
78
78
|
});
|
|
79
79
|
|
|
80
|
-
// With custom
|
|
80
|
+
// With custom browser specifications
|
|
81
81
|
const violations = await checkCompatibility({
|
|
82
82
|
dir: "dist",
|
|
83
83
|
target: "2015",
|
|
@@ -85,10 +85,10 @@ const violations = await checkCompatibility({
|
|
|
85
85
|
});
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
-
### GitHub Actions
|
|
88
|
+
### GitHub Actions Integration
|
|
89
89
|
|
|
90
90
|
```yaml
|
|
91
|
-
name:
|
|
91
|
+
name: Validate Compatibility
|
|
92
92
|
on: [push, pull_request]
|
|
93
93
|
|
|
94
94
|
jobs:
|
|
@@ -108,15 +108,15 @@ jobs:
|
|
|
108
108
|
|
|
109
109
|
### Parameters
|
|
110
110
|
|
|
111
|
-
| Parameter | Description | Default
|
|
112
|
-
| ---------- | ------------------------------------------ |
|
|
113
|
-
| `path` | Directory to scan for JavaScript files | `dist`
|
|
114
|
-
| `target` | Target ES version | `2015`
|
|
115
|
-
| `browsers` | Browser targets for compatibility checking | Auto-
|
|
111
|
+
| Parameter | Description | Default | Required |
|
|
112
|
+
| ---------- | ------------------------------------------ | ------------------------- | -------- |
|
|
113
|
+
| `path` | Directory to scan for JavaScript files | `dist` | No |
|
|
114
|
+
| `target` | Target ES version | `2015` | Yes |
|
|
115
|
+
| `browsers` | Browser targets for compatibility checking | Auto-detected from target | No |
|
|
116
116
|
|
|
117
117
|
### ES Target Versions
|
|
118
118
|
|
|
119
|
-
The `target` parameter
|
|
119
|
+
The `target` parameter supports multiple formats:
|
|
120
120
|
|
|
121
121
|
- **Year format**: `2015`, `2016`, `2017`, etc.
|
|
122
122
|
- **Numeric format**: `6` (ES2015), `7` (ES2016), `11` (ES2020), etc.
|
|
@@ -124,17 +124,17 @@ The `target` parameter accepts multiple formats:
|
|
|
124
124
|
|
|
125
125
|
### Browser Targets
|
|
126
126
|
|
|
127
|
-
The `browsers` parameter
|
|
127
|
+
The `browsers` parameter follows the Browserslist format. When not specified, browsers are automatically determined based on the ES target:
|
|
128
128
|
|
|
129
129
|
- **ES2015/ES6**: `> 1%, last 2 versions, not dead, ie 11`
|
|
130
130
|
- **ES2016-2017/ES7-8**: `> 1%, last 2 versions, not dead, not ie 11`
|
|
131
131
|
- **ES2018-2019/ES9-10**: `> 1%, last 2 versions, not dead, not ie 11, not op_mini all`
|
|
132
132
|
- **ES2020+/ES11+**: `> 1%, last 2 versions, not dead, not ie 11, not op_mini all, not android < 67`
|
|
133
133
|
|
|
134
|
-
Custom browser
|
|
134
|
+
Custom browser target examples:
|
|
135
135
|
|
|
136
|
-
- `> 1%, last 2 versions, not dead, ie 11` - Modern browsers
|
|
137
|
-
- `> 0.5%, last 2 versions, Firefox ESR, not dead` - Broader support
|
|
136
|
+
- `> 1%, last 2 versions, not dead, ie 11` - Modern browsers with IE11 support
|
|
137
|
+
- `> 0.5%, last 2 versions, Firefox ESR, not dead` - Broader browser support
|
|
138
138
|
- `defaults` - Default Browserslist targets
|
|
139
139
|
- `last 1 version` - Latest version of each browser
|
|
140
140
|
|
|
@@ -186,8 +186,8 @@ MIT License - see [LICENSE](LICENSE) file for details.
|
|
|
186
186
|
|
|
187
187
|
1. Fork the repository
|
|
188
188
|
2. Create a feature branch
|
|
189
|
-
3.
|
|
190
|
-
4. Add tests
|
|
189
|
+
3. Implement your changes
|
|
190
|
+
4. Add tests where applicable
|
|
191
191
|
5. Run the linter: `npm run lint`
|
|
192
192
|
6. Submit a pull request
|
|
193
193
|
|
package/dist/lib/detectTarget.js
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import * as path from "path";
|
|
3
3
|
// Shared utilities for ES version parsing and conversion
|
|
4
|
+
const CONFIG_FILE_NAMES = [
|
|
5
|
+
"package.json",
|
|
6
|
+
".browserslistrc",
|
|
7
|
+
".browserslist",
|
|
8
|
+
"tsconfig.json",
|
|
9
|
+
"babel.config.js",
|
|
10
|
+
"babel.config.cjs",
|
|
11
|
+
"babel.config.mjs",
|
|
12
|
+
".babelrc",
|
|
13
|
+
"vite.config.js",
|
|
14
|
+
"vite.config.ts",
|
|
15
|
+
"vite.config.cjs",
|
|
16
|
+
"vite.config.mjs",
|
|
17
|
+
"webpack.config.js",
|
|
18
|
+
"webpack.config.ts",
|
|
19
|
+
"webpack.config.cjs",
|
|
20
|
+
"webpack.config.mjs",
|
|
21
|
+
"next.config.js",
|
|
22
|
+
"next.config.ts",
|
|
23
|
+
"next.config.cjs",
|
|
24
|
+
"next.config.mjs",
|
|
25
|
+
];
|
|
4
26
|
/**
|
|
5
27
|
* Parse ES version from string (e.g., "es6", "es2020", "ES2015")
|
|
6
28
|
* Returns the year as a string, or null if not found
|
|
@@ -53,11 +75,42 @@ const readJsonFile = (filePath) => {
|
|
|
53
75
|
const content = fs.readFileSync(filePath, "utf-8");
|
|
54
76
|
return JSON.parse(content);
|
|
55
77
|
};
|
|
78
|
+
/**
|
|
79
|
+
* Helper to read text file safely
|
|
80
|
+
*/
|
|
81
|
+
const readTextFile = (filePath) => {
|
|
82
|
+
return fs.readFileSync(filePath, "utf-8");
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Helper to safely evaluate JavaScript files (for config files)
|
|
86
|
+
*/
|
|
87
|
+
const evaluateJsFile = (filePath) => {
|
|
88
|
+
const content = readTextFile(filePath);
|
|
89
|
+
// Create a safe evaluation context
|
|
90
|
+
const module = { exports: {} };
|
|
91
|
+
const require = (id) => {
|
|
92
|
+
if (id === "path")
|
|
93
|
+
return path;
|
|
94
|
+
if (id === "fs")
|
|
95
|
+
return fs;
|
|
96
|
+
throw new Error(`Cannot require '${id}' in config evaluation`);
|
|
97
|
+
};
|
|
98
|
+
try {
|
|
99
|
+
// Use Function constructor to create a safe evaluation environment
|
|
100
|
+
const fn = new Function("module", "exports", "require", "path", "fs", "__dirname", content);
|
|
101
|
+
fn(module, module.exports, require, path, fs, path.dirname(filePath));
|
|
102
|
+
return module.exports;
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
console.warn(`Error evaluating ${filePath}:`, error);
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
};
|
|
56
109
|
/**
|
|
57
110
|
* Type guard for package.json structure
|
|
58
111
|
*/
|
|
59
112
|
const isPackageJson = (obj) => {
|
|
60
|
-
return typeof obj === "object" && obj !== null
|
|
113
|
+
return typeof obj === "object" && obj !== null;
|
|
61
114
|
};
|
|
62
115
|
/**
|
|
63
116
|
* Type guard for tsconfig.json structure
|
|
@@ -72,57 +125,121 @@ const isBabelRc = (obj) => {
|
|
|
72
125
|
return typeof obj === "object" && obj !== null && "presets" in obj;
|
|
73
126
|
};
|
|
74
127
|
/**
|
|
75
|
-
*
|
|
128
|
+
* Type guard for vite config structure
|
|
76
129
|
*/
|
|
77
|
-
const
|
|
78
|
-
return
|
|
130
|
+
const isViteConfig = (obj) => {
|
|
131
|
+
return typeof obj === "object" && obj !== null;
|
|
79
132
|
};
|
|
80
133
|
/**
|
|
81
|
-
*
|
|
134
|
+
* Type guard for webpack config structure
|
|
135
|
+
*/
|
|
136
|
+
const isWebpackConfig = (obj) => {
|
|
137
|
+
return typeof obj === "object" && obj !== null;
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* Type guard for next.js config structure
|
|
141
|
+
*/
|
|
142
|
+
const isNextConfig = (obj) => {
|
|
143
|
+
return typeof obj === "object" && obj !== null;
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* Get parser function for a given config file
|
|
147
|
+
*/
|
|
148
|
+
const getParser = (filename) => {
|
|
149
|
+
switch (true) {
|
|
150
|
+
case filename === "package.json":
|
|
151
|
+
return parsePackageJson;
|
|
152
|
+
case filename === ".browserslistrc":
|
|
153
|
+
case filename === ".browserslist":
|
|
154
|
+
return parseBrowserslistFile;
|
|
155
|
+
case filename === "tsconfig.json":
|
|
156
|
+
return parseTsConfig;
|
|
157
|
+
case filename === ".babelrc":
|
|
158
|
+
return parseBabelRc;
|
|
159
|
+
case filename.startsWith("babel.config"):
|
|
160
|
+
return parseBabelConfig;
|
|
161
|
+
case filename.startsWith("vite.config"):
|
|
162
|
+
return parseViteConfig;
|
|
163
|
+
case filename.startsWith("webpack.config"):
|
|
164
|
+
return parseWebpackConfig;
|
|
165
|
+
case filename.startsWith("next.config"):
|
|
166
|
+
return parseNextConfig;
|
|
167
|
+
default:
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
/**
|
|
172
|
+
* Get all possible config file names for detection
|
|
173
|
+
*/
|
|
174
|
+
const getConfigFileNames = () => {
|
|
175
|
+
return CONFIG_FILE_NAMES;
|
|
176
|
+
};
|
|
177
|
+
/**
|
|
178
|
+
* Detects both ES target and output directory from common frontend project configuration files.
|
|
82
179
|
* 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
|
|
180
|
+
* Returns an object with detected target and output directory information
|
|
84
181
|
*/
|
|
85
|
-
export const
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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);
|
|
182
|
+
export const detectTargetAndOutput = (cwd = process.cwd()) => {
|
|
183
|
+
const configFileNames = getConfigFileNames();
|
|
184
|
+
const result = {};
|
|
185
|
+
for (const filename of configFileNames) {
|
|
186
|
+
const filePath = path.join(cwd, filename);
|
|
100
187
|
if (fs.existsSync(filePath)) {
|
|
188
|
+
const parser = getParser(filename);
|
|
189
|
+
if (!parser) {
|
|
190
|
+
console.warn(`No parser found for ${filename}`);
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
101
193
|
try {
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
194
|
+
const detection = parser(filePath);
|
|
195
|
+
// Update target if found and not already set
|
|
196
|
+
if (detection.target && !result.target) {
|
|
197
|
+
result.target = detection.target;
|
|
198
|
+
result.targetSource = filename;
|
|
199
|
+
}
|
|
200
|
+
// Update output directory if found and not already set
|
|
201
|
+
if (detection.outputDir && !result.outputDir) {
|
|
202
|
+
result.outputDir = detection.outputDir;
|
|
203
|
+
result.outputSource = filename;
|
|
204
|
+
}
|
|
205
|
+
// If we found both target and output directory, we can stop searching
|
|
206
|
+
if (result.target && result.outputDir) {
|
|
207
|
+
break;
|
|
105
208
|
}
|
|
106
209
|
}
|
|
107
210
|
catch (error) {
|
|
108
|
-
console.warn(`Error parsing ${
|
|
109
|
-
// Continue to next config file if parsing fails
|
|
211
|
+
console.warn(`Error parsing ${filename}:`, error);
|
|
110
212
|
continue;
|
|
111
213
|
}
|
|
112
214
|
}
|
|
113
215
|
}
|
|
114
|
-
return
|
|
216
|
+
return result;
|
|
217
|
+
};
|
|
218
|
+
/**
|
|
219
|
+
* Legacy function for backward compatibility - detects only ES target
|
|
220
|
+
*/
|
|
221
|
+
export const detectTarget = (cwd = process.cwd()) => {
|
|
222
|
+
const result = detectTargetAndOutput(cwd);
|
|
223
|
+
return result.target ? { target: result.target, source: result.targetSource } : null;
|
|
115
224
|
};
|
|
116
225
|
/**
|
|
117
|
-
*
|
|
226
|
+
* Legacy function for backward compatibility - detects only output directory
|
|
227
|
+
*/
|
|
228
|
+
export const detectOutputDir = (cwd = process.cwd()) => {
|
|
229
|
+
const result = detectTargetAndOutput(cwd);
|
|
230
|
+
return result.outputDir ? { outputDir: result.outputDir, source: result.outputSource } : null;
|
|
231
|
+
};
|
|
232
|
+
/**
|
|
233
|
+
* Parse package.json for both target and output directory
|
|
118
234
|
*/
|
|
119
235
|
const parsePackageJson = (filePath) => {
|
|
120
236
|
const pkg = readJsonFile(filePath);
|
|
121
237
|
if (!isPackageJson(pkg)) {
|
|
122
238
|
console.warn(`Warning: ${filePath} does not look like a valid package.json (missing or invalid browserslist field).`);
|
|
123
|
-
return
|
|
239
|
+
return {};
|
|
124
240
|
}
|
|
125
|
-
|
|
241
|
+
const result = {};
|
|
242
|
+
// Check for browserslist field for target
|
|
126
243
|
if (pkg.browserslist) {
|
|
127
244
|
const browserslist = Array.isArray(pkg.browserslist) ? pkg.browserslist : [pkg.browserslist];
|
|
128
245
|
// Look for ES target in browserslist
|
|
@@ -130,32 +247,52 @@ const parsePackageJson = (filePath) => {
|
|
|
130
247
|
if (typeof browser === "string") {
|
|
131
248
|
const target = parseESVersion(browser);
|
|
132
249
|
if (target) {
|
|
133
|
-
|
|
250
|
+
result.target = target;
|
|
251
|
+
break;
|
|
134
252
|
}
|
|
135
253
|
}
|
|
136
254
|
}
|
|
137
255
|
}
|
|
138
|
-
//
|
|
139
|
-
|
|
140
|
-
|
|
256
|
+
// Check for output directory hints
|
|
257
|
+
if (pkg.dist) {
|
|
258
|
+
result.outputDir = pkg.dist;
|
|
259
|
+
}
|
|
260
|
+
else if (pkg.build) {
|
|
261
|
+
result.outputDir = pkg.build;
|
|
262
|
+
}
|
|
263
|
+
else if (pkg.main && pkg.main.startsWith("./dist/")) {
|
|
264
|
+
result.outputDir = "dist";
|
|
265
|
+
}
|
|
266
|
+
else if (pkg.dependencies?.next || pkg.devDependencies?.next) {
|
|
267
|
+
// Next.js apps default to .next directory
|
|
268
|
+
result.outputDir = ".next/static";
|
|
269
|
+
}
|
|
270
|
+
return result;
|
|
141
271
|
};
|
|
142
272
|
/**
|
|
143
|
-
* Parse tsconfig.json for target
|
|
273
|
+
* Parse tsconfig.json for both target and output directory
|
|
144
274
|
*/
|
|
145
275
|
const parseTsConfig = (filePath) => {
|
|
146
276
|
const config = readJsonFile(filePath);
|
|
147
277
|
if (!isTsConfig(config)) {
|
|
148
278
|
console.warn(`Warning: ${filePath} does not look like a valid tsconfig.json (missing or invalid compilerOptions field).`);
|
|
149
|
-
return
|
|
279
|
+
return {};
|
|
150
280
|
}
|
|
281
|
+
const result = {};
|
|
151
282
|
if (config.compilerOptions?.target) {
|
|
152
283
|
const target = config.compilerOptions.target;
|
|
153
|
-
|
|
284
|
+
const mappedTarget = TARGET_MAP[target];
|
|
285
|
+
if (mappedTarget) {
|
|
286
|
+
result.target = mappedTarget;
|
|
287
|
+
}
|
|
154
288
|
}
|
|
155
|
-
|
|
289
|
+
if (config.compilerOptions?.outDir) {
|
|
290
|
+
result.outputDir = config.compilerOptions.outDir;
|
|
291
|
+
}
|
|
292
|
+
return result;
|
|
156
293
|
};
|
|
157
294
|
/**
|
|
158
|
-
* Parse babel.config.js for
|
|
295
|
+
* Parse babel.config.js for target
|
|
159
296
|
*/
|
|
160
297
|
const parseBabelConfig = (filePath) => {
|
|
161
298
|
const content = readTextFile(filePath);
|
|
@@ -167,19 +304,22 @@ const parseBabelConfig = (filePath) => {
|
|
|
167
304
|
const browsersMatch = targetsStr.match(/browsers.*?\[(.*?)\]/);
|
|
168
305
|
if (browsersMatch) {
|
|
169
306
|
const browsers = browsersMatch[1];
|
|
170
|
-
|
|
307
|
+
const target = parseESVersion(browsers);
|
|
308
|
+
if (target) {
|
|
309
|
+
return { target };
|
|
310
|
+
}
|
|
171
311
|
}
|
|
172
312
|
}
|
|
173
|
-
return
|
|
313
|
+
return {};
|
|
174
314
|
};
|
|
175
315
|
/**
|
|
176
|
-
* Parse .babelrc for
|
|
316
|
+
* Parse .babelrc for target
|
|
177
317
|
*/
|
|
178
318
|
const parseBabelRc = (filePath) => {
|
|
179
319
|
const config = readJsonFile(filePath);
|
|
180
320
|
if (!isBabelRc(config)) {
|
|
181
321
|
console.warn(`Warning: ${filePath} does not look like a valid .babelrc (missing or invalid presets field).`);
|
|
182
|
-
return
|
|
322
|
+
return {};
|
|
183
323
|
}
|
|
184
324
|
if (config.presets) {
|
|
185
325
|
for (const preset of config.presets) {
|
|
@@ -190,40 +330,61 @@ const parseBabelRc = (filePath) => {
|
|
|
190
330
|
for (const browser of browsers) {
|
|
191
331
|
const target = parseESVersion(browser);
|
|
192
332
|
if (target) {
|
|
193
|
-
return target;
|
|
333
|
+
return { target };
|
|
194
334
|
}
|
|
195
335
|
}
|
|
196
336
|
}
|
|
197
337
|
}
|
|
198
338
|
}
|
|
199
339
|
}
|
|
200
|
-
return
|
|
340
|
+
return {};
|
|
201
341
|
};
|
|
202
342
|
/**
|
|
203
|
-
* Parse vite.config.js/ts for target
|
|
343
|
+
* Parse vite.config.js/ts for both target and output directory
|
|
204
344
|
*/
|
|
205
345
|
const parseViteConfig = (filePath) => {
|
|
206
346
|
const content = readTextFile(filePath);
|
|
207
|
-
|
|
347
|
+
const config = evaluateJsFile(filePath);
|
|
348
|
+
const result = {};
|
|
349
|
+
// Look for esbuild target
|
|
208
350
|
const esbuildMatch = content.match(/esbuild\s*:\s*\{[^}]*target\s*:\s*['"`]([^'"`]+)['"`]/s);
|
|
209
351
|
if (esbuildMatch) {
|
|
210
352
|
const target = esbuildMatch[1];
|
|
211
|
-
|
|
353
|
+
const mappedTarget = TARGET_MAP[target];
|
|
354
|
+
if (mappedTarget) {
|
|
355
|
+
result.target = mappedTarget;
|
|
356
|
+
}
|
|
212
357
|
}
|
|
213
|
-
|
|
358
|
+
// Look for output directory
|
|
359
|
+
if (isViteConfig(config) && config.build?.outDir) {
|
|
360
|
+
result.outputDir = config.build.outDir;
|
|
361
|
+
}
|
|
362
|
+
return result;
|
|
214
363
|
};
|
|
215
364
|
/**
|
|
216
|
-
* Parse webpack.config.js/ts for target
|
|
365
|
+
* Parse webpack.config.js/ts for both target and output directory
|
|
217
366
|
*/
|
|
218
367
|
const parseWebpackConfig = (filePath) => {
|
|
219
368
|
const content = readTextFile(filePath);
|
|
369
|
+
const config = evaluateJsFile(filePath);
|
|
370
|
+
const result = {};
|
|
220
371
|
// Look for target configuration
|
|
221
372
|
const targetMatch = content.match(/target.*?['"`]([^'"`]+)['"`]/);
|
|
222
373
|
if (targetMatch) {
|
|
223
374
|
const target = targetMatch[1];
|
|
224
|
-
|
|
375
|
+
const mappedTarget = TARGET_MAP[target];
|
|
376
|
+
if (mappedTarget) {
|
|
377
|
+
result.target = mappedTarget;
|
|
378
|
+
}
|
|
225
379
|
}
|
|
226
|
-
|
|
380
|
+
// Look for output directory
|
|
381
|
+
if (isWebpackConfig(config) && config.output?.path) {
|
|
382
|
+
// Extract just the directory name from the path
|
|
383
|
+
const outputPath = config.output.path;
|
|
384
|
+
const dirName = path.basename(outputPath);
|
|
385
|
+
result.outputDir = dirName;
|
|
386
|
+
}
|
|
387
|
+
return result;
|
|
227
388
|
};
|
|
228
389
|
/**
|
|
229
390
|
* Parse .browserslistrc or .browserslist file for ES target
|
|
@@ -237,8 +398,27 @@ const parseBrowserslistFile = (filePath) => {
|
|
|
237
398
|
for (const browser of lines) {
|
|
238
399
|
const target = parseESVersion(browser);
|
|
239
400
|
if (target) {
|
|
240
|
-
return target;
|
|
401
|
+
return { target };
|
|
241
402
|
}
|
|
242
403
|
}
|
|
243
|
-
return
|
|
404
|
+
return {};
|
|
405
|
+
};
|
|
406
|
+
/**
|
|
407
|
+
* Parse next.config.js/ts/cjs/mjs for output directory
|
|
408
|
+
*/
|
|
409
|
+
const parseNextConfig = (filePath) => {
|
|
410
|
+
const config = evaluateJsFile(filePath);
|
|
411
|
+
if (!isNextConfig(config)) {
|
|
412
|
+
return {};
|
|
413
|
+
}
|
|
414
|
+
const result = {};
|
|
415
|
+
// Next.js uses .next as default output directory
|
|
416
|
+
if (config.distDir) {
|
|
417
|
+
result.outputDir = config.distDir;
|
|
418
|
+
}
|
|
419
|
+
else {
|
|
420
|
+
// Default Next.js output directory
|
|
421
|
+
result.outputDir = ".next";
|
|
422
|
+
}
|
|
423
|
+
return result;
|
|
244
424
|
};
|