@michaelhelvey/vite-config 1.0.0 → 1.0.2
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 -48
- package/dist/index.d.mts +32 -0
- package/dist/index.mjs +144 -0
- package/dist/index.mjs.map +1 -0
- package/dist/rules-CnWlgdks.mjs +6316 -0
- package/dist/rules-CnWlgdks.mjs.map +1 -0
- package/dist/rules-DdF6uL2A.d.mts +5613 -0
- package/dist/rules.d.mts +2 -0
- package/dist/rules.mjs +2 -0
- package/package.json +6 -1
- package/bun.lock +0 -319
- package/scripts/scrape-rules.ts +0 -86
- package/src/index.ts +0 -144
- package/src/rules.ts +0 -6436
- package/tsconfig.json +0 -11
- package/vite.config.ts +0 -19
package/README.md
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# @michaelhelvey/vite-config
|
|
2
2
|
|
|
3
|
-
Opinionated
|
|
4
|
-
TypeScript projects. One import gives you sane formatting, linting, testing, and pre-commit hook
|
|
5
|
-
configuration — no per-project bikeshedding required.
|
|
3
|
+
Opinionated defaults for [Vite+](https://viteplus.dev/).
|
|
6
4
|
|
|
7
5
|
## Install
|
|
8
6
|
|
|
@@ -24,51 +22,6 @@ export default defineConfig({
|
|
|
24
22
|
});
|
|
25
23
|
```
|
|
26
24
|
|
|
27
|
-
That's it. You now have working `vp fmt`, `vp check`, and `vp test` commands with the defaults
|
|
28
|
-
below, plus a pre-commit hook that runs `vp check --fix` on staged files.
|
|
29
|
-
|
|
30
|
-
## What's included
|
|
31
|
-
|
|
32
|
-
### Formatting (`fmt`)
|
|
33
|
-
|
|
34
|
-
Powered by [oxfmt](https://github.com/nicolo-ribaudo/oxfmt) via vite-plus:
|
|
35
|
-
|
|
36
|
-
- 100 character print width
|
|
37
|
-
- Semicolons, double quotes, trailing commas
|
|
38
|
-
- 2-space indentation, no tabs
|
|
39
|
-
- Prose wrapping enabled
|
|
40
|
-
- Import sorting (builtin → third-party → everything else)
|
|
41
|
-
|
|
42
|
-
### Linting (`lint`)
|
|
43
|
-
|
|
44
|
-
Powered by [oxlint](https://oxc.rs) via vite-plus, with type-aware checking enabled. Rules are
|
|
45
|
-
selected by filtering the full oxlint rule set against a curated combination of plugins and
|
|
46
|
-
categories:
|
|
47
|
-
|
|
48
|
-
| Preset | Plugins | Categories |
|
|
49
|
-
| ------------------ | ------------------------------------------------------------- | ----------------------------- |
|
|
50
|
-
| `production_node` | eslint, oxc, typescript, promise | correctness, perf, suspicious |
|
|
51
|
-
| `production_react` | eslint, oxc, typescript, promise, react, react-perf, jsx-a11y | correctness, perf, suspicious |
|
|
52
|
-
| `test` | eslint, oxc, promise, vitest | correctness |
|
|
53
|
-
|
|
54
|
-
File-level overrides apply automatically:
|
|
55
|
-
|
|
56
|
-
- `**/*.tsx` files use the `production_react` preset
|
|
57
|
-
- `*/*.test.*` files use the `test` preset
|
|
58
|
-
- Everything else uses `production_node`
|
|
59
|
-
|
|
60
|
-
Ignore patterns are read from your repository's `.gitignore` at config load time.
|
|
61
|
-
|
|
62
|
-
### Testing (`test`)
|
|
63
|
-
|
|
64
|
-
- Pass with no test files
|
|
65
|
-
- Unstub globals and env vars between tests
|
|
66
|
-
- Reset mocks between tests
|
|
67
|
-
|
|
68
|
-
### Pre-commit (`staged`)
|
|
69
|
-
|
|
70
|
-
All staged files are run through `vp check --fix` before each commit.
|
|
71
|
-
|
|
72
25
|
## Customization
|
|
73
26
|
|
|
74
27
|
### Extending the default config
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { t as RULES } from "./rules-DdF6uL2A.mjs";
|
|
2
|
+
import { UserConfig } from "vite-plus";
|
|
3
|
+
|
|
4
|
+
//#region src/index.d.ts
|
|
5
|
+
type OxlintPluginType = (typeof RULES)[number]["scope"];
|
|
6
|
+
type OxlintCategoryType = (typeof RULES)[number]["category"];
|
|
7
|
+
interface CustomDefaultsEntry {
|
|
8
|
+
categories: OxlintCategoryType[];
|
|
9
|
+
plugins: OxlintPluginType[];
|
|
10
|
+
}
|
|
11
|
+
interface CustomDefaults {
|
|
12
|
+
production_node: CustomDefaultsEntry;
|
|
13
|
+
production_react: CustomDefaultsEntry;
|
|
14
|
+
test: CustomDefaultsEntry;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Mapping from a broad category of code "e.g. nodejs production code" to a list of categories and
|
|
18
|
+
* oxlint plugins to enable.
|
|
19
|
+
*/
|
|
20
|
+
declare const customOxlintDefaults: CustomDefaults;
|
|
21
|
+
type CustomOxlintCategory = keyof typeof customOxlintDefaults;
|
|
22
|
+
/**
|
|
23
|
+
* Finds the root of the git repository, then loads any .gitignore files there, then returns a list
|
|
24
|
+
* of glob patterns from it. Doesn't handle GIT_DIR or worktrees or any weird shit.
|
|
25
|
+
*/
|
|
26
|
+
declare const ignoresFromGitIgnore: () => Promise<string[]>;
|
|
27
|
+
declare const pluginsForCategory: (category: CustomOxlintCategory) => ("eslint" | "import" | "jest" | "jsdoc" | "jsx-a11y" | "nextjs" | "node" | "oxc" | "promise" | "react" | "react-perf" | "typescript" | "unicorn" | "vitest" | "vue")[];
|
|
28
|
+
declare const rulesForCategory: (category: CustomOxlintCategory) => Record<string, "error">;
|
|
29
|
+
declare const DEFAULT_USER_CONFIG: UserConfig;
|
|
30
|
+
//#endregion
|
|
31
|
+
export { customOxlintDefaults, DEFAULT_USER_CONFIG as default, ignoresFromGitIgnore, pluginsForCategory, rulesForCategory };
|
|
32
|
+
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { t as RULES } from "./rules-CnWlgdks.mjs";
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
//#region src/index.ts
|
|
6
|
+
/**
|
|
7
|
+
* Mapping from a broad category of code "e.g. nodejs production code" to a list of categories and
|
|
8
|
+
* oxlint plugins to enable.
|
|
9
|
+
*/
|
|
10
|
+
const customOxlintDefaults = {
|
|
11
|
+
production_node: {
|
|
12
|
+
categories: [
|
|
13
|
+
"correctness",
|
|
14
|
+
"perf",
|
|
15
|
+
"suspicious"
|
|
16
|
+
],
|
|
17
|
+
plugins: [
|
|
18
|
+
"eslint",
|
|
19
|
+
"oxc",
|
|
20
|
+
"typescript",
|
|
21
|
+
"promise"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
production_react: {
|
|
25
|
+
categories: [
|
|
26
|
+
"correctness",
|
|
27
|
+
"perf",
|
|
28
|
+
"suspicious"
|
|
29
|
+
],
|
|
30
|
+
plugins: [
|
|
31
|
+
"eslint",
|
|
32
|
+
"oxc",
|
|
33
|
+
"typescript",
|
|
34
|
+
"promise",
|
|
35
|
+
"react",
|
|
36
|
+
"react-perf",
|
|
37
|
+
"jsx-a11y"
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
test: {
|
|
41
|
+
categories: ["correctness"],
|
|
42
|
+
plugins: [
|
|
43
|
+
"eslint",
|
|
44
|
+
"oxc",
|
|
45
|
+
"promise",
|
|
46
|
+
"vitest"
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Finds the root of the git repository, then loads any .gitignore files there, then returns a list
|
|
52
|
+
* of glob patterns from it. Doesn't handle GIT_DIR or worktrees or any weird shit.
|
|
53
|
+
*/
|
|
54
|
+
const ignoresFromGitIgnore = async () => {
|
|
55
|
+
const gitRoot = await new Promise((resolve, reject) => {
|
|
56
|
+
const cp = spawn("git", ["rev-parse", "--show-toplevel"], { stdio: "pipe" });
|
|
57
|
+
cp.on("error", reject);
|
|
58
|
+
cp.stdout?.on("data", (pathBuf) => {
|
|
59
|
+
resolve(pathBuf.toString("utf-8").trim());
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
const gitIgnorePath = path.join(gitRoot, ".gitignore");
|
|
63
|
+
if (await fs.promises.access(gitIgnorePath, fs.constants.R_OK).then(() => true).catch(() => false)) return (await fs.promises.readFile(gitIgnorePath, "utf-8")).split(/\s/);
|
|
64
|
+
return [];
|
|
65
|
+
};
|
|
66
|
+
const pluginsForCategory = (category) => customOxlintDefaults[category].plugins;
|
|
67
|
+
const rulesForCategory = (category) => {
|
|
68
|
+
const rules = {};
|
|
69
|
+
const config = customOxlintDefaults[category];
|
|
70
|
+
for (const rule of RULES) if (config.plugins.includes(rule.scope) && config.categories.includes(rule.category)) rules[`${rule.scope}/${rule.value}`] = "error";
|
|
71
|
+
return rules;
|
|
72
|
+
};
|
|
73
|
+
const DEFAULT_USER_CONFIG = {
|
|
74
|
+
staged: { "*": "vp check --fix" },
|
|
75
|
+
fmt: {
|
|
76
|
+
sortImports: {
|
|
77
|
+
customGroups: [
|
|
78
|
+
{
|
|
79
|
+
groupName: "builtin",
|
|
80
|
+
selector: "builtin"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
groupName: "thirdparty",
|
|
84
|
+
selector: "external"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
groupName: "everything-else",
|
|
88
|
+
elementNamePattern: ["*"]
|
|
89
|
+
}
|
|
90
|
+
],
|
|
91
|
+
newlinesBetween: false,
|
|
92
|
+
sortPackageJson: true
|
|
93
|
+
},
|
|
94
|
+
printWidth: 100,
|
|
95
|
+
proseWrap: "always",
|
|
96
|
+
semi: true,
|
|
97
|
+
singleQuote: false,
|
|
98
|
+
tabWidth: 2,
|
|
99
|
+
trailingComma: "all",
|
|
100
|
+
useTabs: false
|
|
101
|
+
},
|
|
102
|
+
lint: {
|
|
103
|
+
env: {
|
|
104
|
+
browser: true,
|
|
105
|
+
builtin: true,
|
|
106
|
+
es2024: true,
|
|
107
|
+
node: true
|
|
108
|
+
},
|
|
109
|
+
ignorePatterns: await ignoresFromGitIgnore(),
|
|
110
|
+
plugins: pluginsForCategory("production_node"),
|
|
111
|
+
rules: {
|
|
112
|
+
...rulesForCategory("production_node"),
|
|
113
|
+
"typescript/consistent-type-imports": ["error", {
|
|
114
|
+
fixStyle: "separate-type-imports",
|
|
115
|
+
prefer: "type-imports"
|
|
116
|
+
}],
|
|
117
|
+
"eslint/no-shadow": "off",
|
|
118
|
+
"typescript/no-unsafe-type-assertion": "off"
|
|
119
|
+
},
|
|
120
|
+
overrides: [{
|
|
121
|
+
files: ["**/*.tsx"],
|
|
122
|
+
plugins: pluginsForCategory("production_react"),
|
|
123
|
+
rules: rulesForCategory("production_react")
|
|
124
|
+
}, {
|
|
125
|
+
files: ["*/*.test.*"],
|
|
126
|
+
plugins: pluginsForCategory("test"),
|
|
127
|
+
rules: rulesForCategory("test")
|
|
128
|
+
}],
|
|
129
|
+
options: {
|
|
130
|
+
typeAware: true,
|
|
131
|
+
typeCheck: true
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
test: {
|
|
135
|
+
passWithNoTests: true,
|
|
136
|
+
unstubGlobals: true,
|
|
137
|
+
unstubEnvs: true,
|
|
138
|
+
mockReset: true
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
//#endregion
|
|
142
|
+
export { customOxlintDefaults, DEFAULT_USER_CONFIG as default, ignoresFromGitIgnore, pluginsForCategory, rulesForCategory };
|
|
143
|
+
|
|
144
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { UserConfig } from \"vite-plus\";\nimport { RULES } from \"./rules.ts\";\n\ntype OxlintPluginType = (typeof RULES)[number][\"scope\"];\ntype OxlintCategoryType = (typeof RULES)[number][\"category\"];\n\ninterface CustomDefaultsEntry {\n categories: OxlintCategoryType[];\n plugins: OxlintPluginType[];\n}\n\ninterface CustomDefaults {\n production_node: CustomDefaultsEntry;\n production_react: CustomDefaultsEntry;\n test: CustomDefaultsEntry;\n}\n\n/**\n * Mapping from a broad category of code \"e.g. nodejs production code\" to a list of categories and\n * oxlint plugins to enable.\n */\nexport const customOxlintDefaults: CustomDefaults = {\n production_node: {\n categories: [\"correctness\", \"perf\", \"suspicious\"],\n plugins: [\"eslint\", \"oxc\", \"typescript\", \"promise\"],\n },\n production_react: {\n categories: [\"correctness\", \"perf\", \"suspicious\"],\n plugins: [\"eslint\", \"oxc\", \"typescript\", \"promise\", \"react\", \"react-perf\", \"jsx-a11y\"],\n },\n test: {\n categories: [\"correctness\"],\n plugins: [\"eslint\", \"oxc\", \"promise\", \"vitest\"],\n },\n};\n\ntype CustomOxlintCategory = keyof typeof customOxlintDefaults;\n\n/**\n * Finds the root of the git repository, then loads any .gitignore files there, then returns a list\n * of glob patterns from it. Doesn't handle GIT_DIR or worktrees or any weird shit.\n */\nexport const ignoresFromGitIgnore = async (): Promise<string[]> => {\n const gitRoot = await new Promise<string>((resolve, reject) => {\n const cp = spawn(\"git\", [\"rev-parse\", \"--show-toplevel\"], { stdio: \"pipe\" });\n cp.on(\"error\", reject);\n\n cp.stdout?.on(\"data\", (pathBuf: Buffer) => {\n resolve(pathBuf.toString(\"utf-8\").trim());\n });\n });\n\n const gitIgnorePath = path.join(gitRoot, \".gitignore\");\n const gitIgnoreExists = await fs.promises\n .access(gitIgnorePath, fs.constants.R_OK)\n .then(() => true)\n .catch(() => false);\n\n if (gitIgnoreExists) {\n const gitIgnoreContents = await fs.promises.readFile(gitIgnorePath, \"utf-8\");\n return gitIgnoreContents.split(/\\s/);\n }\n\n return [];\n};\n\nexport const pluginsForCategory = (category: CustomOxlintCategory) =>\n customOxlintDefaults[category].plugins;\nexport const rulesForCategory = (category: CustomOxlintCategory) => {\n const rules: Record<string, \"error\"> = {};\n const config = customOxlintDefaults[category];\n\n for (const rule of RULES) {\n if (config.plugins.includes(rule.scope) && config.categories.includes(rule.category)) {\n rules[`${rule.scope}/${rule.value}`] = \"error\";\n }\n }\n\n return rules;\n};\n\nconst DEFAULT_STAGED: UserConfig[\"staged\"] = {\n \"*\": \"vp check --fix\",\n};\n\nconst DEFAULT_FMT: UserConfig[\"fmt\"] = {\n sortImports: {\n customGroups: [\n { groupName: \"builtin\", selector: \"builtin\" },\n { groupName: \"thirdparty\", selector: \"external\" },\n { groupName: \"everything-else\", elementNamePattern: [\"*\"] },\n ],\n newlinesBetween: false,\n sortPackageJson: true,\n },\n printWidth: 100,\n proseWrap: \"always\",\n semi: true,\n singleQuote: false,\n tabWidth: 2,\n trailingComma: \"all\",\n useTabs: false,\n};\n\nconst DEFAULT_LINT: UserConfig[\"lint\"] = {\n env: {\n browser: true,\n builtin: true,\n es2024: true,\n node: true,\n },\n ignorePatterns: await ignoresFromGitIgnore(),\n plugins: pluginsForCategory(\"production_node\"),\n rules: {\n ...rulesForCategory(\"production_node\"),\n \"typescript/consistent-type-imports\": [\n \"error\",\n { fixStyle: \"separate-type-imports\", prefer: \"type-imports\" },\n ],\n \"eslint/no-shadow\": \"off\",\n \"typescript/no-unsafe-type-assertion\": \"off\",\n },\n overrides: [\n {\n files: [\"**/*.tsx\"],\n plugins: pluginsForCategory(\"production_react\"),\n rules: rulesForCategory(\"production_react\"),\n },\n {\n files: [\"*/*.test.*\"],\n plugins: pluginsForCategory(\"test\"),\n rules: rulesForCategory(\"test\"),\n },\n ],\n options: {\n typeAware: true,\n typeCheck: true,\n },\n};\n\nconst DEFAULT_TEST: UserConfig[\"test\"] = {\n passWithNoTests: true,\n unstubGlobals: true,\n unstubEnvs: true,\n mockReset: true,\n};\n\nconst DEFAULT_USER_CONFIG: UserConfig = {\n staged: DEFAULT_STAGED,\n fmt: DEFAULT_FMT,\n lint: DEFAULT_LINT,\n test: DEFAULT_TEST,\n};\n\nexport default DEFAULT_USER_CONFIG;\n"],"mappings":";;;;;;;;;AAwBA,MAAa,uBAAuC;CAClD,iBAAiB;EACf,YAAY;GAAC;GAAe;GAAQ;GAAa;EACjD,SAAS;GAAC;GAAU;GAAO;GAAc;GAAU;EACpD;CACD,kBAAkB;EAChB,YAAY;GAAC;GAAe;GAAQ;GAAa;EACjD,SAAS;GAAC;GAAU;GAAO;GAAc;GAAW;GAAS;GAAc;GAAW;EACvF;CACD,MAAM;EACJ,YAAY,CAAC,cAAc;EAC3B,SAAS;GAAC;GAAU;GAAO;GAAW;GAAS;EAChD;CACF;;;;;AAQD,MAAa,uBAAuB,YAA+B;CACjE,MAAM,UAAU,MAAM,IAAI,SAAiB,SAAS,WAAW;EAC7D,MAAM,KAAK,MAAM,OAAO,CAAC,aAAa,kBAAkB,EAAE,EAAE,OAAO,QAAQ,CAAC;AAC5E,KAAG,GAAG,SAAS,OAAO;AAEtB,KAAG,QAAQ,GAAG,SAAS,YAAoB;AACzC,WAAQ,QAAQ,SAAS,QAAQ,CAAC,MAAM,CAAC;IACzC;GACF;CAEF,MAAM,gBAAgB,KAAK,KAAK,SAAS,aAAa;AAMtD,KALwB,MAAM,GAAG,SAC9B,OAAO,eAAe,GAAG,UAAU,KAAK,CACxC,WAAW,KAAK,CAChB,YAAY,MAAM,CAInB,SAD0B,MAAM,GAAG,SAAS,SAAS,eAAe,QAAQ,EACnD,MAAM,KAAK;AAGtC,QAAO,EAAE;;AAGX,MAAa,sBAAsB,aACjC,qBAAqB,UAAU;AACjC,MAAa,oBAAoB,aAAmC;CAClE,MAAM,QAAiC,EAAE;CACzC,MAAM,SAAS,qBAAqB;AAEpC,MAAK,MAAM,QAAQ,MACjB,KAAI,OAAO,QAAQ,SAAS,KAAK,MAAM,IAAI,OAAO,WAAW,SAAS,KAAK,SAAS,CAClF,OAAM,GAAG,KAAK,MAAM,GAAG,KAAK,WAAW;AAI3C,QAAO;;AAqET,MAAM,sBAAkC;CACtC,QAnE2C,EAC3C,KAAK,kBACN;CAkEC,KAhEqC;EACrC,aAAa;GACX,cAAc;IACZ;KAAE,WAAW;KAAW,UAAU;KAAW;IAC7C;KAAE,WAAW;KAAc,UAAU;KAAY;IACjD;KAAE,WAAW;KAAmB,oBAAoB,CAAC,IAAI;KAAE;IAC5D;GACD,iBAAiB;GACjB,iBAAiB;GAClB;EACD,YAAY;EACZ,WAAW;EACX,MAAM;EACN,aAAa;EACb,UAAU;EACV,eAAe;EACf,SAAS;EACV;CAgDC,MA9CuC;EACvC,KAAK;GACH,SAAS;GACT,SAAS;GACT,QAAQ;GACR,MAAM;GACP;EACD,gBAAgB,MAAM,sBAAsB;EAC5C,SAAS,mBAAmB,kBAAkB;EAC9C,OAAO;GACL,GAAG,iBAAiB,kBAAkB;GACtC,sCAAsC,CACpC,SACA;IAAE,UAAU;IAAyB,QAAQ;IAAgB,CAC9D;GACD,oBAAoB;GACpB,uCAAuC;GACxC;EACD,WAAW,CACT;GACE,OAAO,CAAC,WAAW;GACnB,SAAS,mBAAmB,mBAAmB;GAC/C,OAAO,iBAAiB,mBAAmB;GAC5C,EACD;GACE,OAAO,CAAC,aAAa;GACrB,SAAS,mBAAmB,OAAO;GACnC,OAAO,iBAAiB,OAAO;GAChC,CACF;EACD,SAAS;GACP,WAAW;GACX,WAAW;GACZ;EACF;CAaC,MAXuC;EACvC,iBAAiB;EACjB,eAAe;EACf,YAAY;EACZ,WAAW;EACZ;CAOA"}
|