@octohash/eslint-config 0.1.3 → 0.2.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/dist/index.mjs ADDED
@@ -0,0 +1,269 @@
1
+ import antfu, { GLOB_HTML, GLOB_SRC, GLOB_VUE, ensurePackages, interopDefault } from "@antfu/eslint-config";
2
+ import catalogsSort, { configs } from "eslint-plugin-catalogs-sort";
3
+ import { readFile } from "node:fs/promises";
4
+ import { getPackageInfo } from "local-pkg";
5
+ import { basename, dirname, resolve } from "pathe";
6
+ import { glob } from "tinyglobby";
7
+ import process from "node:process";
8
+ import { findUp } from "find-up-simple";
9
+
10
+ //#region src/configs/octohash.ts
11
+ async function octohash() {
12
+ return [{
13
+ name: "octohash/octohash/rules",
14
+ rules: { "pnpm/yaml-enforce-settings": "off" }
15
+ }];
16
+ }
17
+
18
+ //#endregion
19
+ //#region src/configs/sort.ts
20
+ async function sortPackageJson() {
21
+ return [
22
+ {
23
+ name: "octohash/sort/setup",
24
+ plugins: { "catalogs-sort": catalogsSort }
25
+ },
26
+ {
27
+ name: "octohash/sort/package-json",
28
+ files: ["**/package.json"],
29
+ rules: { "jsonc/sort-keys": [
30
+ "error",
31
+ {
32
+ order: [
33
+ "publisher",
34
+ "name",
35
+ "displayName",
36
+ "type",
37
+ "version",
38
+ "private",
39
+ "packageManager",
40
+ "description",
41
+ "author",
42
+ "contributors",
43
+ "license",
44
+ "funding",
45
+ "homepage",
46
+ "repository",
47
+ "bugs",
48
+ "keywords",
49
+ "categories",
50
+ "sideEffects",
51
+ "imports",
52
+ "exports",
53
+ "main",
54
+ "module",
55
+ "unpkg",
56
+ "jsdelivr",
57
+ "types",
58
+ "typesVersions",
59
+ "bin",
60
+ "icon",
61
+ "files",
62
+ "engines",
63
+ "activationEvents",
64
+ "contributes",
65
+ "scripts",
66
+ "peerDependencies",
67
+ "peerDependenciesMeta",
68
+ "dependencies",
69
+ "optionalDependencies",
70
+ "devDependencies",
71
+ "pnpm",
72
+ "overrides",
73
+ "resolutions",
74
+ "husky",
75
+ "simple-git-hooks",
76
+ "lint-staged",
77
+ "eslintConfig"
78
+ ],
79
+ pathPattern: "^$"
80
+ },
81
+ {
82
+ order: { type: "asc" },
83
+ pathPattern: "^workspaces\\.catalog$"
84
+ },
85
+ {
86
+ order: { type: "asc" },
87
+ pathPattern: "^workspaces\\.catalogs\\.[^.]+$"
88
+ },
89
+ {
90
+ order: [
91
+ "types",
92
+ "import",
93
+ "require",
94
+ "default"
95
+ ],
96
+ pathPattern: "^exports.*$"
97
+ },
98
+ {
99
+ order: [
100
+ "pre-commit",
101
+ "prepare-commit-msg",
102
+ "commit-msg",
103
+ "post-commit",
104
+ "pre-rebase",
105
+ "post-rewrite",
106
+ "post-checkout",
107
+ "post-merge",
108
+ "pre-push",
109
+ "pre-auto-gc"
110
+ ],
111
+ pathPattern: "^(?:gitHooks|husky|simple-git-hooks)$"
112
+ }
113
+ ] }
114
+ },
115
+ ...configs.recommended
116
+ ];
117
+ }
118
+
119
+ //#endregion
120
+ //#region src/constants.ts
121
+ const DEFAULT_IGNORE_PATHS = [
122
+ "**/.git/**",
123
+ "**/.next/**",
124
+ "**/.nuxt/**",
125
+ "**/.output/**",
126
+ "**/.vercel/**",
127
+ "**/.vscode/**",
128
+ "**/.idea/**",
129
+ "**/coverage/**",
130
+ "**/dist/**",
131
+ "**/build/**",
132
+ "**/node_modules/**",
133
+ "**/dist/**",
134
+ "**/public/**",
135
+ "**/fixture/**",
136
+ "**/fixtures/**"
137
+ ];
138
+ const REPOSITORY_ROOT_FILES = [
139
+ ".git",
140
+ "package-lock.json",
141
+ "npm-shrinkwrap.json",
142
+ "pnpm-lock.yaml",
143
+ "pnpm-workspace.yaml",
144
+ "yarn.lock",
145
+ "bun.lock",
146
+ "bun.lockb",
147
+ "deno.lock"
148
+ ];
149
+ const TAILWIND_V3_CONFIG_PATTERNS = [
150
+ "**/tailwind.config.ts",
151
+ "**/tailwind.config.mjs",
152
+ "**/tailwind.config.cjs",
153
+ "**/tailwind.config.js"
154
+ ];
155
+ const TAILWIND_V4_IMPORT_RE = /@import\s+['"]tailwindcss(?:\/[^'"]*)?['"]/;
156
+
157
+ //#endregion
158
+ //#region src/utils.ts
159
+ async function findRepositoryRoot() {
160
+ for (const file of REPOSITORY_ROOT_FILES) {
161
+ const filepath = await findUp(file, file === ".git" ? { type: "directory" } : void 0);
162
+ if (filepath) return dirname(filepath);
163
+ }
164
+ return process.cwd();
165
+ }
166
+ function pathDepth(filepath) {
167
+ return filepath.split("/").length;
168
+ }
169
+
170
+ //#endregion
171
+ //#region src/configs/tailwindcss.ts
172
+ async function tailwindcss(options = {}) {
173
+ const pkg = await getPackageInfo("tailwindcss");
174
+ if (!pkg || !pkg.version) return [];
175
+ await ensurePackages(["eslint-plugin-better-tailwindcss"]);
176
+ const version = pkg.version;
177
+ const { files = [
178
+ GLOB_HTML,
179
+ GLOB_SRC,
180
+ GLOB_VUE
181
+ ], overrides = {}, settings = {} } = options;
182
+ const resolvedSettings = await resolveTailwindSettings(settings, version);
183
+ return [{
184
+ name: "octohash/tailwindcss/setup",
185
+ plugins: { tailwindcss: await interopDefault(import("eslint-plugin-better-tailwindcss")) }
186
+ }, {
187
+ files,
188
+ name: "octohash/tailwindcss/rules",
189
+ rules: {
190
+ "tailwindcss/enforce-consistent-line-wrapping": "error",
191
+ "tailwindcss/enforce-consistent-class-order": "error",
192
+ "tailwindcss/enforce-consistent-variable-syntax": "error",
193
+ "tailwindcss/enforce-consistent-important-position": "error",
194
+ "tailwindcss/enforce-shorthand-classes": "error",
195
+ "tailwindcss/enforce-canonical-classes": "error",
196
+ "tailwindcss/no-duplicate-classes": "error",
197
+ "tailwindcss/no-deprecated-classes": "error",
198
+ "tailwindcss/no-unnecessary-whitespace": "error",
199
+ "tailwindcss/no-conflicting-classes": "error",
200
+ ...overrides
201
+ },
202
+ settings: { "better-tailwindcss": resolvedSettings }
203
+ }];
204
+ }
205
+ async function resolveTailwindSettings(settings, version) {
206
+ const resolvedSettings = { ...settings ?? {} };
207
+ const major = Number.parseInt(version, 10);
208
+ const cwd = await findRepositoryRoot();
209
+ if (major === 4 && !resolvedSettings.entryPoint) resolvedSettings.entryPoint = await findTailwindV4ImportCSS(cwd) ?? void 0;
210
+ if (major === 3 && !resolvedSettings.tailwindConfig) resolvedSettings.tailwindConfig = await findTailwindV3Config(cwd) ?? void 0;
211
+ return resolvedSettings;
212
+ }
213
+ async function findTailwindV3Config(cwd) {
214
+ const files = await glob(TAILWIND_V3_CONFIG_PATTERNS, {
215
+ cwd,
216
+ ignore: DEFAULT_IGNORE_PATHS,
217
+ onlyFiles: true
218
+ });
219
+ if (files.length === 0) return void 0;
220
+ const extensionPriority = new Map(TAILWIND_V3_CONFIG_PATTERNS.map((pattern, index) => [basename(pattern), index]));
221
+ files.sort((a, b) => {
222
+ const depthDiff = pathDepth(a) - pathDepth(b);
223
+ if (depthDiff !== 0) return depthDiff;
224
+ return (extensionPriority.get(basename(a)) ?? Number.POSITIVE_INFINITY) - (extensionPriority.get(basename(b)) ?? Number.POSITIVE_INFINITY);
225
+ });
226
+ return resolve(cwd, files[0]);
227
+ }
228
+ async function findTailwindV4ImportCSS(cwd) {
229
+ const files = await glob("**/*.css", {
230
+ cwd,
231
+ ignore: DEFAULT_IGNORE_PATHS,
232
+ onlyFiles: true
233
+ });
234
+ files.sort((a, b) => pathDepth(a) - pathDepth(b));
235
+ for (const file of files) {
236
+ const fullPath = resolve(cwd, file);
237
+ if (await hasTailwindV4Import(fullPath)) return fullPath;
238
+ }
239
+ }
240
+ async function hasTailwindV4Import(filePath) {
241
+ try {
242
+ const content = await readFile(filePath, "utf-8");
243
+ return TAILWIND_V4_IMPORT_RE.test(content);
244
+ } catch {
245
+ return false;
246
+ }
247
+ }
248
+
249
+ //#endregion
250
+ //#region src/index.ts
251
+ function defineConfig(options, ...userConfigs) {
252
+ const { formatters } = options || {};
253
+ const config = antfu(mergeOptions(options), ...userConfigs);
254
+ if (formatters === false) return config;
255
+ const enableTailwindCSS = typeof options?.formatters === "boolean" || options?.formatters?.tailwindcss;
256
+ if (enableTailwindCSS) config.append(tailwindcss(typeof enableTailwindCSS === "boolean" ? {} : enableTailwindCSS)).renamePlugins({ "better-tailwindcss": "tailwindcss" });
257
+ config.append(sortPackageJson());
258
+ config.append(octohash());
259
+ return config;
260
+ }
261
+ function mergeOptions(options) {
262
+ return {
263
+ ...options,
264
+ formatters: { ...typeof options?.formatters === "object" ? options.formatters : {} }
265
+ };
266
+ }
267
+
268
+ //#endregion
269
+ export { defineConfig };
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@octohash/eslint-config",
3
3
  "type": "module",
4
- "version": "0.1.3",
5
- "description": "ESLint configuration based on @antfu/eslint-config, includes built-in support for Tailwind CSS v4.",
4
+ "version": "0.2.1",
5
+ "description": "Personal ESLint config based on @antfu/eslint-config with opinionated extensions.",
6
6
  "author": "jinghaihan",
7
7
  "license": "MIT",
8
8
  "homepage": "https://github.com/jinghaihan/eslint-config#readme",
@@ -19,11 +19,9 @@
19
19
  "linter"
20
20
  ],
21
21
  "exports": {
22
- ".": "./dist/index.js",
22
+ ".": "./dist/index.mjs",
23
23
  "./package.json": "./package.json"
24
24
  },
25
- "main": "./dist/index.js",
26
- "module": "./dist/index.js",
27
25
  "types": "./dist/index.d.ts",
28
26
  "publishConfig": {
29
27
  "access": "public"
@@ -31,28 +29,37 @@
31
29
  "files": [
32
30
  "dist"
33
31
  ],
32
+ "peerDependencies": {
33
+ "eslint-plugin-better-tailwindcss": ">=4.2.0"
34
+ },
35
+ "peerDependenciesMeta": {
36
+ "eslint-plugin-better-tailwindcss": {
37
+ "optional": true
38
+ }
39
+ },
34
40
  "dependencies": {
35
- "@antfu/eslint-config": "^5.2.1",
36
- "eslint-plugin-format": "^1.0.1",
37
- "eslint-plugin-tailwindcss": "^4.0.0-beta.0",
41
+ "@antfu/eslint-config": "^7.4.3",
42
+ "eslint-plugin-catalogs-sort": "^0.0.0-alpha.0",
43
+ "find-up-simple": "^1.0.1",
38
44
  "local-pkg": "^1.1.2",
39
- "pathe": "^2.0.3"
45
+ "pathe": "^2.0.3",
46
+ "tinyglobby": "^0.2.15"
40
47
  },
41
48
  "devDependencies": {
49
+ "tsdown": "^0.20.3",
42
50
  "@octohash/tsconfig": "^0.2.0",
43
- "@types/eslint-plugin-tailwindcss": "^3.17.0",
44
- "@types/node": "^24.3.0",
45
- "bumpp": "^10.2.3",
46
- "eslint": "^9.34.0",
47
- "eslint-flat-config-utils": "^2.1.1",
48
- "lint-staged": "^16.1.5",
49
- "pncat": "^0.5.0",
51
+ "bumpp": "^10.4.1",
52
+ "pncat": "^0.10.2",
50
53
  "simple-git-hooks": "^2.13.1",
51
- "taze": "^19.3.0",
52
- "tsdown": "^0.14.2",
53
- "typescript": "^5.9.2",
54
- "vitest": "^3.2.4",
55
- "@octohash/eslint-config": "0.1.3"
54
+ "taze": "^19.9.2",
55
+ "typescript": "^5.9.3",
56
+ "eslint": "^10.0.0",
57
+ "eslint-flat-config-utils": "^3.0.1",
58
+ "eslint-plugin-better-tailwindcss": "^4.2.0",
59
+ "lint-staged": "^16.2.7",
60
+ "vitest": "^4.0.18",
61
+ "@types/node": "^24.10.13",
62
+ "@octohash/eslint-config": "0.2.1"
56
63
  },
57
64
  "simple-git-hooks": {
58
65
  "pre-commit": "pnpm lint-staged"
@@ -61,14 +68,13 @@
61
68
  "*": "eslint --fix"
62
69
  },
63
70
  "scripts": {
64
- "build": "tsdown --clean --dts",
71
+ "build": "tsdown",
65
72
  "typecheck": "tsc",
66
73
  "test": "vitest",
67
74
  "lint": "eslint",
68
75
  "deps": "taze major -I",
69
- "release": "bumpp && pnpm publish --no-git-checks",
76
+ "release": "bumpp",
70
77
  "catalog": "pncat",
71
- "bootstrap": "pnpm install",
72
- "preinstall": "npx only-allow pnpm"
78
+ "bootstrap": "pnpm install"
73
79
  }
74
80
  }
package/dist/index.d.ts DELETED
@@ -1,15 +0,0 @@
1
- import * as _antfu_eslint_config0 from "@antfu/eslint-config";
2
- import { Awaitable, OptionsConfig, TypedFlatConfigItem } from "@antfu/eslint-config";
3
- import * as eslint_flat_config_utils0 from "eslint-flat-config-utils";
4
- import { FlatConfigComposer } from "eslint-flat-config-utils";
5
- import { Linter } from "eslint";
6
-
7
- //#region src/types.d.ts
8
- type Options = AntfuOptions & {};
9
- type AntfuOptions = OptionsConfig & Omit<TypedFlatConfigItem, 'files'>;
10
- type UserConfig = Awaitable<TypedFlatConfigItem | TypedFlatConfigItem[] | FlatConfigComposer<any, any> | Linter.Config[]>[];
11
- //#endregion
12
- //#region src/index.d.ts
13
- declare function defineConfig(options?: Options, ...userConfigs: UserConfig): eslint_flat_config_utils0.FlatConfigComposer<_antfu_eslint_config0.TypedFlatConfigItem, _antfu_eslint_config0.ConfigNames>;
14
- //#endregion
15
- export { defineConfig };
package/dist/index.js DELETED
@@ -1,52 +0,0 @@
1
- import antfu from "@antfu/eslint-config";
2
- import { readFileSync, readdirSync } from "node:fs";
3
- import process from "node:process";
4
- import tailwindPlugin from "eslint-plugin-tailwindcss";
5
- import { isPackageExists } from "local-pkg";
6
- import { join } from "pathe";
7
-
8
- //#region src/tailwindcss.ts
9
- function tailwindCSS(dir) {
10
- const installed = isPackageExists("tailwindcss");
11
- if (!installed) return [];
12
- const config = findTailwindImportCSS(dir ?? process.cwd());
13
- if (!config) return [];
14
- return {
15
- ...tailwindPlugin.configs["flat/recommended"],
16
- settings: { tailwindcss: { config } }
17
- };
18
- }
19
- function findTailwindImportCSS(dir) {
20
- const entries = readdirSync(dir, { withFileTypes: true });
21
- for (const entry of entries) {
22
- const fullPath = join(dir, entry.name);
23
- if (entry.isDirectory()) {
24
- const found = findTailwindImportCSS(fullPath);
25
- if (found) return found;
26
- } else if (entry.isFile() && entry.name.endsWith(".css")) {
27
- const lines = readFileSync(fullPath, "utf8").split(/\r?\n/);
28
- for (const line of lines) if (line.trim().startsWith("@import \"tailwindcss")) return fullPath;
29
- }
30
- }
31
- return null;
32
- }
33
-
34
- //#endregion
35
- //#region src/index.ts
36
- function defineConfig(options, ...userConfigs) {
37
- return antfu(mergeOptions(options), tailwindCSS(), ...userConfigs);
38
- }
39
- function mergeOptions(options) {
40
- return {
41
- ...options,
42
- stylistic: true,
43
- formatters: {
44
- css: true,
45
- html: true,
46
- ...typeof options?.formatters === "object" ? options.formatters : {}
47
- }
48
- };
49
- }
50
-
51
- //#endregion
52
- export { defineConfig };