@michaelhelvey/vite-config 1.0.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/src/index.ts ADDED
@@ -0,0 +1,144 @@
1
+ import { spawn } from "node:child_process";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import type { UserConfig } from "vite-plus";
5
+ import { RULES } from "./rules.ts";
6
+
7
+ type OxlintPluginType = (typeof RULES)[number]["scope"];
8
+ type OxlintCategoryType = (typeof RULES)[number]["category"];
9
+
10
+ interface CustomDefaultsEntry {
11
+ categories: OxlintCategoryType[];
12
+ plugins: OxlintPluginType[];
13
+ }
14
+
15
+ interface CustomDefaults {
16
+ production_node: CustomDefaultsEntry;
17
+ production_react: CustomDefaultsEntry;
18
+ test: CustomDefaultsEntry;
19
+ }
20
+
21
+ /**
22
+ * Mapping from a broad category of code "e.g. nodejs production code" to a list of categories and
23
+ * oxlint plugins to enable.
24
+ */
25
+ export const customOxlintDefaults: CustomDefaults = {
26
+ production_node: {
27
+ categories: ["correctness", "perf", "suspicious"],
28
+ plugins: ["eslint", "oxc", "typescript", "promise"],
29
+ },
30
+ production_react: {
31
+ categories: ["correctness", "perf", "suspicious"],
32
+ plugins: ["eslint", "oxc", "typescript", "promise", "react", "react-perf", "jsx-a11y"],
33
+ },
34
+ test: {
35
+ categories: ["correctness"],
36
+ plugins: ["eslint", "oxc", "promise", "vitest"],
37
+ },
38
+ };
39
+
40
+ type CustomOxlintCategory = keyof typeof customOxlintDefaults;
41
+
42
+ /**
43
+ * Finds the root of the git repository, then loads any .gitignore files there, then returns a list
44
+ * of glob patterns from it. Doesn't handle GIT_DIR or worktrees or any weird shit.
45
+ */
46
+ export const ignoresFromGitIgnore = async (): Promise<string[]> => {
47
+ const gitRoot = await new Promise<string>((resolve, reject) => {
48
+ const cp = spawn("git", ["rev-parse", "--show-toplevel"], { stdio: "pipe" });
49
+ cp.on("error", reject);
50
+
51
+ cp.stdout?.on("data", (pathBuf: Buffer) => {
52
+ resolve(pathBuf.toString("utf-8").trim());
53
+ });
54
+ });
55
+
56
+ const gitIgnorePath = path.join(gitRoot, ".gitignore");
57
+ const gitIgnoreExists = await fs.promises
58
+ .access(gitIgnorePath, fs.constants.R_OK)
59
+ .then(() => true)
60
+ .catch(() => false);
61
+
62
+ if (gitIgnoreExists) {
63
+ const gitIgnoreContents = await fs.promises.readFile(gitIgnorePath, "utf-8");
64
+ return gitIgnoreContents.split(/\s/);
65
+ }
66
+
67
+ return [];
68
+ };
69
+
70
+ export const pluginsForCategory = (category: CustomOxlintCategory) =>
71
+ customOxlintDefaults[category].plugins;
72
+ export const rulesForCategory = (category: CustomOxlintCategory) => {
73
+ const rules: Record<string, "error"> = {};
74
+ const config = customOxlintDefaults[category];
75
+
76
+ for (const rule of RULES) {
77
+ if (config.plugins.includes(rule.scope) && config.categories.includes(rule.category)) {
78
+ rules[`${rule.scope}/${rule.value}`] = "error";
79
+ }
80
+ }
81
+
82
+ return rules;
83
+ };
84
+
85
+ const DEFAULT_STAGED: UserConfig["staged"] = {
86
+ "*": "vp check --fix",
87
+ };
88
+
89
+ const DEFAULT_FMT: UserConfig["fmt"] = {
90
+ sortImports: {
91
+ customGroups: [
92
+ { groupName: "builtin", selector: "builtin" },
93
+ { groupName: "thirdparty", selector: "external" },
94
+ { groupName: "everything-else", elementNamePattern: ["*"] },
95
+ ],
96
+ newlinesBetween: false,
97
+ sortPackageJson: true,
98
+ },
99
+ printWidth: 100,
100
+ proseWrap: "always",
101
+ semi: true,
102
+ singleQuote: false,
103
+ tabWidth: 2,
104
+ trailingComma: "all",
105
+ useTabs: false,
106
+ };
107
+
108
+ const DEFAULT_LINT: UserConfig["lint"] = {
109
+ ignorePatterns: await ignoresFromGitIgnore(),
110
+ plugins: pluginsForCategory("production_node"),
111
+ rules: rulesForCategory("production_node"),
112
+ overrides: [
113
+ {
114
+ files: ["**/*.tsx"],
115
+ plugins: pluginsForCategory("production_react"),
116
+ rules: rulesForCategory("production_react"),
117
+ },
118
+ {
119
+ files: ["*/*.test.*"],
120
+ plugins: pluginsForCategory("test"),
121
+ rules: rulesForCategory("test"),
122
+ },
123
+ ],
124
+ options: {
125
+ typeAware: true,
126
+ typeCheck: true,
127
+ },
128
+ };
129
+
130
+ const DEFAULT_TEST: UserConfig["test"] = {
131
+ passWithNoTests: true,
132
+ unstubGlobals: true,
133
+ unstubEnvs: true,
134
+ mockReset: true,
135
+ };
136
+
137
+ const DEFAULT_USER_CONFIG: UserConfig = {
138
+ staged: DEFAULT_STAGED,
139
+ fmt: DEFAULT_FMT,
140
+ lint: DEFAULT_LINT,
141
+ test: DEFAULT_TEST,
142
+ };
143
+
144
+ export default DEFAULT_USER_CONFIG;