@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 CHANGED
@@ -1,8 +1,6 @@
1
1
  # @michaelhelvey/vite-config
2
2
 
3
- Opinionated, shareable [vite-plus](https://github.com/nicolo-ribaudo/vite-plus) defaults for
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
@@ -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"}