eslint-plugin-next-compat 1.0.0-alpha.1

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 ADDED
@@ -0,0 +1,105 @@
1
+ # eslint-plugin-next-compat
2
+
3
+ ESLint plugin that automatically detects **client components only** in Next.js App Router projects and checks browser compatibility.
4
+
5
+ ## Why?
6
+
7
+ In Next.js App Router, server and client components coexist. Browser compatibility checks are only needed for **client components**, but existing tools can't distinguish between them.
8
+
9
+ This plugin detects client components and **tracks all their dependencies**, ensuring complete coverage of client-side code.
10
+
11
+ ## Installation
12
+
13
+ > **Requirements**
14
+ > ESLint 9+ (Flat Config only)
15
+
16
+ ```bash
17
+ npm install eslint-plugin-next-compat --save-dev
18
+ # or
19
+ pnpm add -D eslint-plugin-next-compat
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ > **Note**
25
+ > Client files are detected when ESLint starts. If you add or remove client components, restart your ESLint server (or IDE) to detect the changes.
26
+
27
+ This plugin uses [eslint-plugin-compat](https://github.com/amilajack/eslint-plugin-compat) internally, so all of its configuration options are supported.
28
+
29
+ ### Basic
30
+
31
+ ```js
32
+ // eslint.config.js
33
+ import nextCompat from 'eslint-plugin-next-compat';
34
+
35
+ export default [
36
+ ...nextCompat.configs.recommended,
37
+ ];
38
+ ```
39
+
40
+ ### With Options
41
+
42
+ ```js
43
+ // eslint.config.js
44
+ import nextCompat from 'eslint-plugin-next-compat';
45
+
46
+ export default [
47
+ ...nextCompat.configs.recommended({
48
+ include: ['src/hooks/**', 'src/utils/client/**'],
49
+ exclude: ['**/*.test.ts', '**/legacy/**'],
50
+ }),
51
+ ];
52
+ ```
53
+
54
+ | Option | Type | Description |
55
+ |--------|------|-------------|
56
+ | `include` | `string[]` | Additional glob patterns to check |
57
+ | `exclude` | `string[]` | Glob patterns to exclude from checking |
58
+
59
+ ### Strict Mode
60
+
61
+ Use `error` instead of `warn`:
62
+
63
+ ```js
64
+ export default [
65
+ ...nextCompat.configs.strict,
66
+ ];
67
+ ```
68
+
69
+ ### Target Browsers
70
+
71
+ Configure via `.browserslistrc` or `browserslist` field in `package.json`:
72
+
73
+ ```
74
+ # .browserslistrc
75
+ last 2 versions
76
+ not dead
77
+ not ie 11
78
+ ```
79
+
80
+ ### Polyfills
81
+
82
+ Exclude APIs that are already polyfilled:
83
+
84
+ ```js
85
+ // eslint.config.js
86
+ export default [
87
+ ...nextCompat.configs.recommended,
88
+ {
89
+ settings: {
90
+ polyfills: ['fetch', 'Promise', 'IntersectionObserver'],
91
+ },
92
+ },
93
+ ];
94
+ ```
95
+
96
+ ## How It Works
97
+
98
+ 1. Scans all `.tsx` files in `src/app` directory
99
+ 2. Identifies files with `'use client'` directive
100
+ 3. Analyzes dependency tree of those files
101
+ 4. Applies [eslint-plugin-compat](https://github.com/amilajack/eslint-plugin-compat) rules to identified client files
102
+
103
+ ## License
104
+
105
+ MIT
package/dist/index.js ADDED
@@ -0,0 +1,227 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __commonJS = (cb, mod) => function __require() {
8
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
+ };
10
+ var __export = (target, all) => {
11
+ for (var name2 in all)
12
+ __defProp(target, name2, { get: all[name2], enumerable: true });
13
+ };
14
+ var __copyProps = (to, from, except, desc) => {
15
+ if (from && typeof from === "object" || typeof from === "function") {
16
+ for (let key of __getOwnPropNames(from))
17
+ if (!__hasOwnProp.call(to, key) && key !== except)
18
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
19
+ }
20
+ return to;
21
+ };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
23
+ // If the importer is in node compatibility mode or this is not an ESM
24
+ // file that has been converted to a CommonJS file using a Babel-
25
+ // compatible transform (i.e. "__esModule" has not been set), then set
26
+ // "default" to the CommonJS "module.exports" for node compatibility.
27
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
28
+ mod
29
+ ));
30
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
31
+
32
+ // package.json
33
+ var require_package = __commonJS({
34
+ "package.json"(exports2, module2) {
35
+ module2.exports = {
36
+ name: "eslint-plugin-next-compat",
37
+ version: "1.0.0-alpha.1",
38
+ description: "ESLint plugin for browser compatibility checking in Next.js App Router client components",
39
+ main: "dist/index.js",
40
+ module: "dist/index.mjs",
41
+ exports: {
42
+ ".": {
43
+ import: "./dist/index.mjs",
44
+ require: "./dist/index.js"
45
+ }
46
+ },
47
+ files: [
48
+ "dist"
49
+ ],
50
+ scripts: {
51
+ build: "tsup",
52
+ dev: "tsup --watch",
53
+ test: "vitest run",
54
+ "test:watch": "vitest",
55
+ prepublishOnly: "pnpm run build",
56
+ deploy: "pnpm run test && pnpm run build && npm publish --access=public"
57
+ },
58
+ keywords: [
59
+ "eslint",
60
+ "eslintplugin",
61
+ "eslint-plugin",
62
+ "next",
63
+ "nextjs",
64
+ "compat",
65
+ "browser-compatibility"
66
+ ],
67
+ author: "dkpark10",
68
+ license: "MIT",
69
+ repository: {
70
+ type: "git",
71
+ url: "https://github.com/dkpark10/eslint-plugin-next-compat"
72
+ },
73
+ homepage: "https://github.com/dkpark10/eslint-plugin-next-compat#readme",
74
+ bugs: {
75
+ url: "https://github.com/dkpark10/eslint-plugin-next-compat/issues"
76
+ },
77
+ peerDependencies: {
78
+ eslint: "^9.0.0"
79
+ },
80
+ dependencies: {
81
+ "dependency-tree": "^11.4.0",
82
+ "eslint-plugin-compat": "^6.0.0",
83
+ glob: "^13.0.6",
84
+ minimatch: "^10.2.4"
85
+ },
86
+ devDependencies: {
87
+ eslint: "^9.0.0",
88
+ tsup: "^8.0.0",
89
+ vitest: "^1.6.0"
90
+ },
91
+ engines: {
92
+ node: ">=18.18.0"
93
+ }
94
+ };
95
+ }
96
+ });
97
+
98
+ // src/index.js
99
+ var index_exports = {};
100
+ __export(index_exports, {
101
+ default: () => index_default,
102
+ plugin: () => plugin
103
+ });
104
+ module.exports = __toCommonJS(index_exports);
105
+ var import_glob2 = require("glob");
106
+ var import_minimatch = require("minimatch");
107
+
108
+ // src/get-client-files.js
109
+ var import_glob = require("glob");
110
+ var import_fs = __toESM(require("fs"));
111
+ var import_path = __toESM(require("path"));
112
+ var import_dependency_tree = __toESM(require("dependency-tree"));
113
+ var USE_CLIENT_REGEX = /^(?:\s|\/\/[^\n]*\n|\/\*[\s\S]*?\*\/)*['"]use client['"]/;
114
+ function getClientFiles(options = {}) {
115
+ const {
116
+ appDir = "src/app",
117
+ cwd = process.cwd(),
118
+ tsConfigPath = "tsconfig.json"
119
+ } = options;
120
+ try {
121
+ let getDependencies = function(fileList) {
122
+ return fileList.reduce(
123
+ (acc, filePath) => {
124
+ try {
125
+ const deps = import_dependency_tree.default.toList({
126
+ filename: filePath,
127
+ directory: cwd,
128
+ filter: (depPath) => !depPath.includes("node_modules") && !depPath.endsWith(".css") && !depPath.endsWith(".scss"),
129
+ tsConfig: import_fs.default.existsSync(tsConfigFullPath) ? tsConfigFullPath : void 0
130
+ });
131
+ return [...acc, ...deps];
132
+ } catch {
133
+ return acc;
134
+ }
135
+ },
136
+ /** @type {string[]} */
137
+ []
138
+ );
139
+ };
140
+ const srcPath = import_path.default.resolve(cwd, appDir);
141
+ const tsConfigFullPath = import_path.default.resolve(cwd, tsConfigPath);
142
+ const tsxFilePaths = (0, import_glob.globSync)(`${srcPath}/**/*.tsx`, {
143
+ ignore: ["**/node_modules/**"]
144
+ });
145
+ if (tsxFilePaths.length === 0) {
146
+ return [];
147
+ }
148
+ const allDependencies = getDependencies(tsxFilePaths);
149
+ const clientFiles = allDependencies.filter((filePath) => {
150
+ try {
151
+ const content = import_fs.default.readFileSync(filePath, "utf-8");
152
+ return USE_CLIENT_REGEX.test(content);
153
+ } catch {
154
+ return false;
155
+ }
156
+ });
157
+ const clientDependencies = getDependencies(clientFiles);
158
+ const uniqueFiles = [...new Set(clientDependencies)];
159
+ return uniqueFiles.map((filePath) => {
160
+ return import_path.default.relative(cwd, filePath);
161
+ });
162
+ } catch (err) {
163
+ console.error("get-client-files error:", err);
164
+ return [];
165
+ }
166
+ }
167
+
168
+ // src/index.js
169
+ var import_eslint_plugin_compat = __toESM(require("eslint-plugin-compat"));
170
+ var { name, version } = require_package();
171
+ var PLUGIN_NAME = name.replace("eslint-plugin-", "");
172
+ var plugin = {
173
+ meta: {
174
+ name,
175
+ version
176
+ },
177
+ rules: {
178
+ compat: import_eslint_plugin_compat.default.rules.compat
179
+ },
180
+ configs: (
181
+ /** @type {NextCompatPlugin['configs']} */
182
+ {}
183
+ )
184
+ };
185
+ function getTargetFiles(include, exclude) {
186
+ const additionalFiles = (include == null ? void 0 : include.flatMap(
187
+ (pattern) => (0, import_glob2.globSync)(pattern, { ignore: ["**/node_modules/**"] })
188
+ )) ?? [];
189
+ const allFiles = [.../* @__PURE__ */ new Set([...getClientFiles(), ...additionalFiles])];
190
+ const filteredFiles = (exclude == null ? void 0 : exclude.length) ? allFiles.filter((file) => !exclude.some((pattern) => (0, import_minimatch.minimatch)(file, pattern))) : allFiles;
191
+ return filteredFiles.length > 0 ? filteredFiles : ["__no_client_files__"];
192
+ }
193
+ function createConfig(severity, options) {
194
+ const targetFiles = getTargetFiles(options == null ? void 0 : options.include, options == null ? void 0 : options.exclude);
195
+ return [
196
+ {
197
+ name: `${PLUGIN_NAME}/${severity === "warn" ? "recommended" : "strict"}`,
198
+ files: targetFiles,
199
+ plugins: {
200
+ [PLUGIN_NAME]: plugin
201
+ },
202
+ rules: {
203
+ [`${PLUGIN_NAME}/compat`]: severity
204
+ }
205
+ }
206
+ ];
207
+ }
208
+ function createConfigFunction(severity) {
209
+ const fn = (options) => createConfig(severity, options);
210
+ fn[Symbol.iterator] = function* () {
211
+ yield* createConfig(severity);
212
+ };
213
+ return (
214
+ /** @type {ConfigFunction} */
215
+ fn
216
+ );
217
+ }
218
+ plugin.configs = {
219
+ recommended: createConfigFunction("warn"),
220
+ strict: createConfigFunction("error")
221
+ };
222
+ var index_default = plugin;
223
+ // Annotate the CommonJS export names for ESM import in node:
224
+ 0 && (module.exports = {
225
+ plugin
226
+ });
227
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../package.json","../src/index.js","../src/get-client-files.js"],"sourcesContent":["{\n \"name\": \"eslint-plugin-next-compat\",\n \"version\": \"1.0.0-alpha.1\",\n \"description\": \"ESLint plugin for browser compatibility checking in Next.js App Router client components\",\n \"main\": \"dist/index.js\",\n \"module\": \"dist/index.mjs\",\n \"exports\": {\n \".\": {\n \"import\": \"./dist/index.mjs\",\n \"require\": \"./dist/index.js\"\n }\n },\n \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"prepublishOnly\": \"pnpm run build\",\n \"deploy\": \"pnpm run test && pnpm run build && npm publish --access=public\"\n },\n \"keywords\": [\n \"eslint\",\n \"eslintplugin\",\n \"eslint-plugin\",\n \"next\",\n \"nextjs\",\n \"compat\",\n \"browser-compatibility\"\n ],\n \"author\": \"dkpark10\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/dkpark10/eslint-plugin-next-compat\"\n },\n \"homepage\": \"https://github.com/dkpark10/eslint-plugin-next-compat#readme\",\n \"bugs\": {\n \"url\": \"https://github.com/dkpark10/eslint-plugin-next-compat/issues\"\n },\n \"peerDependencies\": {\n \"eslint\": \"^9.0.0\"\n },\n \"dependencies\": {\n \"dependency-tree\": \"^11.4.0\",\n \"eslint-plugin-compat\": \"^6.0.0\",\n \"glob\": \"^13.0.6\",\n \"minimatch\": \"^10.2.4\"\n },\n \"devDependencies\": {\n \"eslint\": \"^9.0.0\",\n \"tsup\": \"^8.0.0\",\n \"vitest\": \"^1.6.0\"\n },\n \"engines\": {\n \"node\": \">=18.18.0\"\n }\n}\n","import { globSync } from 'glob';\nimport { minimatch } from 'minimatch';\nimport { getClientFiles } from './get-client-files.js';\nimport compatPlugin from 'eslint-plugin-compat';\nconst { name, version } = require('../package.json');\n\nconst PLUGIN_NAME = name.replace('eslint-plugin-', '');\n\n/**\n * @typedef {Object} ConfigOptions\n * @property {string[]} [include] - Additional glob patterns to include as client files\n * @property {string[]} [exclude] - Glob patterns to exclude from client files\n */\n\n/**\n * @typedef {((options?: ConfigOptions) => import('eslint').Linter.Config[]) & { [Symbol.iterator](): Generator<import('eslint').Linter.Config> }} ConfigFunction\n */\n\n/**\n * @typedef {Object} NextCompatPlugin\n * @property {{ name: string; version: string }} meta\n * @property {Record<string, import('eslint').Rule.RuleModule>} rules\n * @property {{ recommended: ConfigFunction; strict: ConfigFunction }} configs\n */\n\n/** @type {NextCompatPlugin} */\nconst plugin = {\n meta: {\n name,\n version,\n },\n\n rules: {\n compat: compatPlugin.rules.compat,\n },\n\n configs: /** @type {NextCompatPlugin['configs']} */ ({}),\n};\n\n/**\n * @param {string[]} [include]\n * @param {string[]} [exclude]\n * @returns {string[]}\n */\nfunction getTargetFiles(include, exclude) {\n const additionalFiles = include?.flatMap((pattern) =>\n globSync(pattern, { ignore: ['**/node_modules/**'] })\n ) ?? [];\n\n const allFiles = [...new Set([...getClientFiles(), ...additionalFiles])];\n\n const filteredFiles = exclude?.length\n ? allFiles.filter((file) => !exclude.some((pattern) => minimatch(file, pattern)))\n : allFiles;\n\n return filteredFiles.length > 0 ? filteredFiles : ['__no_client_files__'];\n}\n\n/**\n * @param {'warn' | 'error'} severity\n * @param {ConfigOptions} [options]\n * @returns {import('eslint').Linter.Config[]}\n */\nfunction createConfig(severity, options) {\n const targetFiles = getTargetFiles(options?.include, options?.exclude);\n\n return [\n {\n name: `${PLUGIN_NAME}/${severity === 'warn' ? 'recommended' : 'strict'}`,\n files: targetFiles,\n plugins: {\n [PLUGIN_NAME]: plugin,\n },\n rules: {\n [`${PLUGIN_NAME}/compat`]: severity,\n },\n },\n ];\n}\n\n/**\n * Create a config function that is also iterable (for spread without calling)\n * @param {'warn' | 'error'} severity\n * @returns {ConfigFunction}\n */\nfunction createConfigFunction(severity) {\n /** @param {ConfigOptions} [options] */\n const fn = (options) => createConfig(severity, options);\n\n // Make it iterable so `...configs.recommended` works without ()\n fn[Symbol.iterator] = function* () {\n yield* createConfig(severity);\n };\n\n return /** @type {ConfigFunction} */ (fn);\n}\n\nplugin.configs = {\n recommended: createConfigFunction('warn'),\n strict: createConfigFunction('error'),\n};\n\nexport { plugin };\nexport default plugin;\n","import { globSync } from 'glob';\nimport fs from 'fs';\nimport path from 'path';\nimport dependencyTree from 'dependency-tree';\n\nconst USE_CLIENT_REGEX = /^(?:\\s|\\/\\/[^\\n]*\\n|\\/\\*[\\s\\S]*?\\*\\/)*['\"]use client['\"]/;\n\n/**\n * @typedef {Object} GetClientFilesOptions\n * @property {string} [appDir] - App directory path (default: 'src/app')\n * @property {string} [cwd] - Project root directory (default: process.cwd())\n * @property {string} [tsConfigPath] - tsconfig.json path (default: 'tsconfig.json')\n */\n\n/**\n * Get all client component files including their dependencies\n * @param {GetClientFilesOptions} [options]\n * @returns {string[]}\n */\nexport function getClientFiles(options = {}) {\n const {\n appDir = 'src/app',\n cwd = process.cwd(),\n tsConfigPath = 'tsconfig.json',\n } = options;\n\n try {\n const srcPath = path.resolve(cwd, appDir);\n const tsConfigFullPath = path.resolve(cwd, tsConfigPath);\n\n // Get all tsx files in app directory\n const tsxFilePaths = globSync(`${srcPath}/**/*.tsx`, {\n ignore: ['**/node_modules/**'],\n });\n\n if (tsxFilePaths.length === 0) {\n return [];\n }\n\n /**\n * Get dependencies for a list of files\n * @param {string[]} fileList\n * @returns {string[]}\n */\n function getDependencies(fileList) {\n return fileList.reduce((acc, filePath) => {\n try {\n const deps = dependencyTree.toList({\n filename: filePath,\n directory: cwd,\n filter: (/** @type {string} */ depPath) =>\n !depPath.includes('node_modules') &&\n !depPath.endsWith('.css') &&\n !depPath.endsWith('.scss'),\n tsConfig: fs.existsSync(tsConfigFullPath) ? tsConfigFullPath : undefined,\n });\n return [...acc, ...deps];\n } catch {\n return acc;\n }\n }, /** @type {string[]} */ ([]));\n }\n\n // Get all dependencies from tsx files\n const allDependencies = getDependencies(tsxFilePaths);\n\n // Filter files that have \"use client\" directive\n const clientFiles = allDependencies.filter((filePath) => {\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n return USE_CLIENT_REGEX.test(content);\n } catch {\n return false;\n }\n });\n\n // Get all dependencies of client files (these are also client components)\n const clientDependencies = getDependencies(clientFiles);\n\n // Return unique file paths as relative glob patterns\n const uniqueFiles = [...new Set(clientDependencies)];\n\n // Convert to relative paths for ESLint files pattern\n return uniqueFiles.map((filePath) => {\n return path.relative(cwd, filePath);\n });\n } catch (err) {\n console.error('get-client-files error:', err);\n return [];\n }\n}\n\nexport default getClientFiles;\n"],"mappings":"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","names":["exports","module","import_glob","dependencyTree","fs","path","compatPlugin"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,195 @@
1
+ var __getOwnPropNames = Object.getOwnPropertyNames;
2
+ var __commonJS = (cb, mod) => function __require() {
3
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
4
+ };
5
+
6
+ // package.json
7
+ var require_package = __commonJS({
8
+ "package.json"(exports, module) {
9
+ module.exports = {
10
+ name: "eslint-plugin-next-compat",
11
+ version: "1.0.0-alpha.1",
12
+ description: "ESLint plugin for browser compatibility checking in Next.js App Router client components",
13
+ main: "dist/index.js",
14
+ module: "dist/index.mjs",
15
+ exports: {
16
+ ".": {
17
+ import: "./dist/index.mjs",
18
+ require: "./dist/index.js"
19
+ }
20
+ },
21
+ files: [
22
+ "dist"
23
+ ],
24
+ scripts: {
25
+ build: "tsup",
26
+ dev: "tsup --watch",
27
+ test: "vitest run",
28
+ "test:watch": "vitest",
29
+ prepublishOnly: "pnpm run build",
30
+ deploy: "pnpm run test && pnpm run build && npm publish --access=public"
31
+ },
32
+ keywords: [
33
+ "eslint",
34
+ "eslintplugin",
35
+ "eslint-plugin",
36
+ "next",
37
+ "nextjs",
38
+ "compat",
39
+ "browser-compatibility"
40
+ ],
41
+ author: "dkpark10",
42
+ license: "MIT",
43
+ repository: {
44
+ type: "git",
45
+ url: "https://github.com/dkpark10/eslint-plugin-next-compat"
46
+ },
47
+ homepage: "https://github.com/dkpark10/eslint-plugin-next-compat#readme",
48
+ bugs: {
49
+ url: "https://github.com/dkpark10/eslint-plugin-next-compat/issues"
50
+ },
51
+ peerDependencies: {
52
+ eslint: "^9.0.0"
53
+ },
54
+ dependencies: {
55
+ "dependency-tree": "^11.4.0",
56
+ "eslint-plugin-compat": "^6.0.0",
57
+ glob: "^13.0.6",
58
+ minimatch: "^10.2.4"
59
+ },
60
+ devDependencies: {
61
+ eslint: "^9.0.0",
62
+ tsup: "^8.0.0",
63
+ vitest: "^1.6.0"
64
+ },
65
+ engines: {
66
+ node: ">=18.18.0"
67
+ }
68
+ };
69
+ }
70
+ });
71
+
72
+ // src/index.js
73
+ import { globSync as globSync2 } from "glob";
74
+ import { minimatch } from "minimatch";
75
+
76
+ // src/get-client-files.js
77
+ import { globSync } from "glob";
78
+ import fs from "fs";
79
+ import path from "path";
80
+ import dependencyTree from "dependency-tree";
81
+ var USE_CLIENT_REGEX = /^(?:\s|\/\/[^\n]*\n|\/\*[\s\S]*?\*\/)*['"]use client['"]/;
82
+ function getClientFiles(options = {}) {
83
+ const {
84
+ appDir = "src/app",
85
+ cwd = process.cwd(),
86
+ tsConfigPath = "tsconfig.json"
87
+ } = options;
88
+ try {
89
+ let getDependencies = function(fileList) {
90
+ return fileList.reduce(
91
+ (acc, filePath) => {
92
+ try {
93
+ const deps = dependencyTree.toList({
94
+ filename: filePath,
95
+ directory: cwd,
96
+ filter: (depPath) => !depPath.includes("node_modules") && !depPath.endsWith(".css") && !depPath.endsWith(".scss"),
97
+ tsConfig: fs.existsSync(tsConfigFullPath) ? tsConfigFullPath : void 0
98
+ });
99
+ return [...acc, ...deps];
100
+ } catch {
101
+ return acc;
102
+ }
103
+ },
104
+ /** @type {string[]} */
105
+ []
106
+ );
107
+ };
108
+ const srcPath = path.resolve(cwd, appDir);
109
+ const tsConfigFullPath = path.resolve(cwd, tsConfigPath);
110
+ const tsxFilePaths = globSync(`${srcPath}/**/*.tsx`, {
111
+ ignore: ["**/node_modules/**"]
112
+ });
113
+ if (tsxFilePaths.length === 0) {
114
+ return [];
115
+ }
116
+ const allDependencies = getDependencies(tsxFilePaths);
117
+ const clientFiles = allDependencies.filter((filePath) => {
118
+ try {
119
+ const content = fs.readFileSync(filePath, "utf-8");
120
+ return USE_CLIENT_REGEX.test(content);
121
+ } catch {
122
+ return false;
123
+ }
124
+ });
125
+ const clientDependencies = getDependencies(clientFiles);
126
+ const uniqueFiles = [...new Set(clientDependencies)];
127
+ return uniqueFiles.map((filePath) => {
128
+ return path.relative(cwd, filePath);
129
+ });
130
+ } catch (err) {
131
+ console.error("get-client-files error:", err);
132
+ return [];
133
+ }
134
+ }
135
+
136
+ // src/index.js
137
+ import compatPlugin from "eslint-plugin-compat";
138
+ var { name, version } = require_package();
139
+ var PLUGIN_NAME = name.replace("eslint-plugin-", "");
140
+ var plugin = {
141
+ meta: {
142
+ name,
143
+ version
144
+ },
145
+ rules: {
146
+ compat: compatPlugin.rules.compat
147
+ },
148
+ configs: (
149
+ /** @type {NextCompatPlugin['configs']} */
150
+ {}
151
+ )
152
+ };
153
+ function getTargetFiles(include, exclude) {
154
+ const additionalFiles = (include == null ? void 0 : include.flatMap(
155
+ (pattern) => globSync2(pattern, { ignore: ["**/node_modules/**"] })
156
+ )) ?? [];
157
+ const allFiles = [.../* @__PURE__ */ new Set([...getClientFiles(), ...additionalFiles])];
158
+ const filteredFiles = (exclude == null ? void 0 : exclude.length) ? allFiles.filter((file) => !exclude.some((pattern) => minimatch(file, pattern))) : allFiles;
159
+ return filteredFiles.length > 0 ? filteredFiles : ["__no_client_files__"];
160
+ }
161
+ function createConfig(severity, options) {
162
+ const targetFiles = getTargetFiles(options == null ? void 0 : options.include, options == null ? void 0 : options.exclude);
163
+ return [
164
+ {
165
+ name: `${PLUGIN_NAME}/${severity === "warn" ? "recommended" : "strict"}`,
166
+ files: targetFiles,
167
+ plugins: {
168
+ [PLUGIN_NAME]: plugin
169
+ },
170
+ rules: {
171
+ [`${PLUGIN_NAME}/compat`]: severity
172
+ }
173
+ }
174
+ ];
175
+ }
176
+ function createConfigFunction(severity) {
177
+ const fn = (options) => createConfig(severity, options);
178
+ fn[Symbol.iterator] = function* () {
179
+ yield* createConfig(severity);
180
+ };
181
+ return (
182
+ /** @type {ConfigFunction} */
183
+ fn
184
+ );
185
+ }
186
+ plugin.configs = {
187
+ recommended: createConfigFunction("warn"),
188
+ strict: createConfigFunction("error")
189
+ };
190
+ var index_default = plugin;
191
+ export {
192
+ index_default as default,
193
+ plugin
194
+ };
195
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../package.json","../src/index.js","../src/get-client-files.js"],"sourcesContent":["{\n \"name\": \"eslint-plugin-next-compat\",\n \"version\": \"1.0.0-alpha.1\",\n \"description\": \"ESLint plugin for browser compatibility checking in Next.js App Router client components\",\n \"main\": \"dist/index.js\",\n \"module\": \"dist/index.mjs\",\n \"exports\": {\n \".\": {\n \"import\": \"./dist/index.mjs\",\n \"require\": \"./dist/index.js\"\n }\n },\n \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"prepublishOnly\": \"pnpm run build\",\n \"deploy\": \"pnpm run test && pnpm run build && npm publish --access=public\"\n },\n \"keywords\": [\n \"eslint\",\n \"eslintplugin\",\n \"eslint-plugin\",\n \"next\",\n \"nextjs\",\n \"compat\",\n \"browser-compatibility\"\n ],\n \"author\": \"dkpark10\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/dkpark10/eslint-plugin-next-compat\"\n },\n \"homepage\": \"https://github.com/dkpark10/eslint-plugin-next-compat#readme\",\n \"bugs\": {\n \"url\": \"https://github.com/dkpark10/eslint-plugin-next-compat/issues\"\n },\n \"peerDependencies\": {\n \"eslint\": \"^9.0.0\"\n },\n \"dependencies\": {\n \"dependency-tree\": \"^11.4.0\",\n \"eslint-plugin-compat\": \"^6.0.0\",\n \"glob\": \"^13.0.6\",\n \"minimatch\": \"^10.2.4\"\n },\n \"devDependencies\": {\n \"eslint\": \"^9.0.0\",\n \"tsup\": \"^8.0.0\",\n \"vitest\": \"^1.6.0\"\n },\n \"engines\": {\n \"node\": \">=18.18.0\"\n }\n}\n","import { globSync } from 'glob';\nimport { minimatch } from 'minimatch';\nimport { getClientFiles } from './get-client-files.js';\nimport compatPlugin from 'eslint-plugin-compat';\nconst { name, version } = require('../package.json');\n\nconst PLUGIN_NAME = name.replace('eslint-plugin-', '');\n\n/**\n * @typedef {Object} ConfigOptions\n * @property {string[]} [include] - Additional glob patterns to include as client files\n * @property {string[]} [exclude] - Glob patterns to exclude from client files\n */\n\n/**\n * @typedef {((options?: ConfigOptions) => import('eslint').Linter.Config[]) & { [Symbol.iterator](): Generator<import('eslint').Linter.Config> }} ConfigFunction\n */\n\n/**\n * @typedef {Object} NextCompatPlugin\n * @property {{ name: string; version: string }} meta\n * @property {Record<string, import('eslint').Rule.RuleModule>} rules\n * @property {{ recommended: ConfigFunction; strict: ConfigFunction }} configs\n */\n\n/** @type {NextCompatPlugin} */\nconst plugin = {\n meta: {\n name,\n version,\n },\n\n rules: {\n compat: compatPlugin.rules.compat,\n },\n\n configs: /** @type {NextCompatPlugin['configs']} */ ({}),\n};\n\n/**\n * @param {string[]} [include]\n * @param {string[]} [exclude]\n * @returns {string[]}\n */\nfunction getTargetFiles(include, exclude) {\n const additionalFiles = include?.flatMap((pattern) =>\n globSync(pattern, { ignore: ['**/node_modules/**'] })\n ) ?? [];\n\n const allFiles = [...new Set([...getClientFiles(), ...additionalFiles])];\n\n const filteredFiles = exclude?.length\n ? allFiles.filter((file) => !exclude.some((pattern) => minimatch(file, pattern)))\n : allFiles;\n\n return filteredFiles.length > 0 ? filteredFiles : ['__no_client_files__'];\n}\n\n/**\n * @param {'warn' | 'error'} severity\n * @param {ConfigOptions} [options]\n * @returns {import('eslint').Linter.Config[]}\n */\nfunction createConfig(severity, options) {\n const targetFiles = getTargetFiles(options?.include, options?.exclude);\n\n return [\n {\n name: `${PLUGIN_NAME}/${severity === 'warn' ? 'recommended' : 'strict'}`,\n files: targetFiles,\n plugins: {\n [PLUGIN_NAME]: plugin,\n },\n rules: {\n [`${PLUGIN_NAME}/compat`]: severity,\n },\n },\n ];\n}\n\n/**\n * Create a config function that is also iterable (for spread without calling)\n * @param {'warn' | 'error'} severity\n * @returns {ConfigFunction}\n */\nfunction createConfigFunction(severity) {\n /** @param {ConfigOptions} [options] */\n const fn = (options) => createConfig(severity, options);\n\n // Make it iterable so `...configs.recommended` works without ()\n fn[Symbol.iterator] = function* () {\n yield* createConfig(severity);\n };\n\n return /** @type {ConfigFunction} */ (fn);\n}\n\nplugin.configs = {\n recommended: createConfigFunction('warn'),\n strict: createConfigFunction('error'),\n};\n\nexport { plugin };\nexport default plugin;\n","import { globSync } from 'glob';\nimport fs from 'fs';\nimport path from 'path';\nimport dependencyTree from 'dependency-tree';\n\nconst USE_CLIENT_REGEX = /^(?:\\s|\\/\\/[^\\n]*\\n|\\/\\*[\\s\\S]*?\\*\\/)*['\"]use client['\"]/;\n\n/**\n * @typedef {Object} GetClientFilesOptions\n * @property {string} [appDir] - App directory path (default: 'src/app')\n * @property {string} [cwd] - Project root directory (default: process.cwd())\n * @property {string} [tsConfigPath] - tsconfig.json path (default: 'tsconfig.json')\n */\n\n/**\n * Get all client component files including their dependencies\n * @param {GetClientFilesOptions} [options]\n * @returns {string[]}\n */\nexport function getClientFiles(options = {}) {\n const {\n appDir = 'src/app',\n cwd = process.cwd(),\n tsConfigPath = 'tsconfig.json',\n } = options;\n\n try {\n const srcPath = path.resolve(cwd, appDir);\n const tsConfigFullPath = path.resolve(cwd, tsConfigPath);\n\n // Get all tsx files in app directory\n const tsxFilePaths = globSync(`${srcPath}/**/*.tsx`, {\n ignore: ['**/node_modules/**'],\n });\n\n if (tsxFilePaths.length === 0) {\n return [];\n }\n\n /**\n * Get dependencies for a list of files\n * @param {string[]} fileList\n * @returns {string[]}\n */\n function getDependencies(fileList) {\n return fileList.reduce((acc, filePath) => {\n try {\n const deps = dependencyTree.toList({\n filename: filePath,\n directory: cwd,\n filter: (/** @type {string} */ depPath) =>\n !depPath.includes('node_modules') &&\n !depPath.endsWith('.css') &&\n !depPath.endsWith('.scss'),\n tsConfig: fs.existsSync(tsConfigFullPath) ? tsConfigFullPath : undefined,\n });\n return [...acc, ...deps];\n } catch {\n return acc;\n }\n }, /** @type {string[]} */ ([]));\n }\n\n // Get all dependencies from tsx files\n const allDependencies = getDependencies(tsxFilePaths);\n\n // Filter files that have \"use client\" directive\n const clientFiles = allDependencies.filter((filePath) => {\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n return USE_CLIENT_REGEX.test(content);\n } catch {\n return false;\n }\n });\n\n // Get all dependencies of client files (these are also client components)\n const clientDependencies = getDependencies(clientFiles);\n\n // Return unique file paths as relative glob patterns\n const uniqueFiles = [...new Set(clientDependencies)];\n\n // Convert to relative paths for ESLint files pattern\n return uniqueFiles.map((filePath) => {\n return path.relative(cwd, filePath);\n });\n } catch (err) {\n console.error('get-client-files error:', err);\n return [];\n }\n}\n\nexport default getClientFiles;\n"],"mappings":"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","names":["globSync","globSync"]}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "eslint-plugin-next-compat",
3
+ "version": "1.0.0-alpha.1",
4
+ "description": "ESLint plugin for browser compatibility checking in Next.js App Router client components",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/index.mjs",
10
+ "require": "./dist/index.js"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist"
15
+ ],
16
+ "scripts": {
17
+ "build": "tsup",
18
+ "dev": "tsup --watch",
19
+ "test": "vitest run",
20
+ "test:watch": "vitest",
21
+ "prepublishOnly": "pnpm run build",
22
+ "deploy": "pnpm run test && pnpm run build && npm publish --access=public"
23
+ },
24
+ "keywords": [
25
+ "eslint",
26
+ "eslintplugin",
27
+ "eslint-plugin",
28
+ "next",
29
+ "nextjs",
30
+ "compat",
31
+ "browser-compatibility"
32
+ ],
33
+ "author": "dkpark10",
34
+ "license": "MIT",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/dkpark10/eslint-plugin-next-compat"
38
+ },
39
+ "homepage": "https://github.com/dkpark10/eslint-plugin-next-compat#readme",
40
+ "bugs": {
41
+ "url": "https://github.com/dkpark10/eslint-plugin-next-compat/issues"
42
+ },
43
+ "peerDependencies": {
44
+ "eslint": "^9.0.0"
45
+ },
46
+ "dependencies": {
47
+ "dependency-tree": "^11.4.0",
48
+ "eslint-plugin-compat": "^6.0.0",
49
+ "glob": "^13.0.6",
50
+ "minimatch": "^10.2.4"
51
+ },
52
+ "devDependencies": {
53
+ "eslint": "^9.0.0",
54
+ "tsup": "^8.0.0",
55
+ "vitest": "^1.6.0"
56
+ },
57
+ "engines": {
58
+ "node": ">=18.18.0"
59
+ }
60
+ }