1const GENERAL_TOOLING_PREFIXES: &[&str] = &[
9 "@types/",
10 "eslint",
11 "@typescript-eslint",
12 "husky",
13 "lint-staged",
14 "commitlint",
15 "@commitlint",
16 "stylelint",
17 "postcss",
18 "autoprefixer",
19 "tailwindcss",
20 "@tailwindcss",
21 "@vitest/",
22 "@jest/",
23 "@testing-library/",
24 "@playwright/",
25 "@storybook/",
26 "storybook",
27 "@babel/",
28 "babel-",
29 "@react-native-community/cli",
30 "@react-native/",
31 "secretlint",
32 "@secretlint/",
33 "oxlint",
34 "@semantic-release/",
35 "semantic-release",
36 "@release-it/",
37 "@lerna-lite/",
38 "@changesets/",
39 "@graphql-codegen/",
40 "@rollup/",
41 "@biomejs/",
42 "@electron-forge/",
43 "@electron/",
44 "@formatjs/",
45];
46
47const GENERAL_TOOLING_EXACT: &[&str] = &[
49 "typescript",
50 "prettier",
51 "turbo",
52 "concurrently",
53 "cross-env",
54 "rimraf",
55 "npm-run-all",
56 "npm-run-all2",
57 "nodemon",
58 "ts-node",
59 "tsx",
60 "knip",
61 "fallow",
62 "jest",
63 "vitest",
64 "happy-dom",
65 "jsdom",
66 "vite",
67 "sass",
68 "sass-embedded",
69 "webpack",
70 "webpack-cli",
71 "webpack-dev-server",
72 "esbuild",
73 "rollup",
74 "swc",
75 "@swc/core",
76 "@swc/jest",
77 "terser",
78 "cssnano",
79 "sharp",
80 "release-it",
81 "lerna",
82 "dotenv-cli",
83 "dotenv-flow",
84 "oxfmt",
85 "jscpd",
86 "npm-check-updates",
87 "markdownlint-cli",
88 "npm-package-json-lint",
89 "synp",
90 "flow-bin",
91 "i18next-parser",
92 "i18next-conv",
93 "webpack-bundle-analyzer",
94 "vite-plugin-svgr",
95 "vite-plugin-eslint",
96 "@vitejs/plugin-vue",
97 "@vitejs/plugin-react",
98 "next-sitemap",
99 "tsup",
100 "unbuild",
101 "typedoc",
102 "nx",
103 "@manypkg/cli",
104 "vue-tsc",
105 "@vue/tsconfig",
106 "@tsconfig/node20",
107 "@tsconfig/react-native",
108 "@typescript/native-preview",
109 "tw-animate-css",
110 "@ianvs/prettier-plugin-sort-imports",
111 "prettier-plugin-tailwindcss",
112 "prettier-plugin-organize-imports",
113 "@vitejs/plugin-react-swc",
114 "@vitejs/plugin-legacy",
115 "rolldown",
116 "rolldown-vite",
117 "oxc-transform",
118 "puppeteer",
119 "madge",
120 "patch-package",
121 "electron",
122 "electron-builder",
123 "electron-vite",
124];
125
126pub fn is_known_tooling_dependency(name: &str) -> bool {
132 GENERAL_TOOLING_PREFIXES.iter().any(|p| name.starts_with(p))
133 || GENERAL_TOOLING_EXACT.contains(&name)
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139
140 #[test]
143 fn types_prefix_matches_scoped() {
144 assert!(is_known_tooling_dependency("@types/node"));
145 assert!(is_known_tooling_dependency("@types/react"));
146 assert!(is_known_tooling_dependency("@types/express"));
147 }
148
149 #[test]
150 fn types_prefix_does_not_match_similar_names() {
151 assert!(!is_known_tooling_dependency("type-fest"));
153 assert!(!is_known_tooling_dependency("typesafe-actions"));
154 }
155
156 #[test]
157 fn storybook_prefix_matches() {
158 assert!(is_known_tooling_dependency("@storybook/react"));
159 assert!(is_known_tooling_dependency("@storybook/addon-essentials"));
160 assert!(is_known_tooling_dependency("storybook"));
161 }
162
163 #[test]
164 fn testing_library_prefix_matches() {
165 assert!(is_known_tooling_dependency("@testing-library/react"));
166 assert!(is_known_tooling_dependency("@testing-library/jest-dom"));
167 }
168
169 #[test]
170 fn babel_prefix_matches() {
171 assert!(is_known_tooling_dependency("@babel/core"));
172 assert!(is_known_tooling_dependency("babel-loader"));
173 assert!(is_known_tooling_dependency("babel-jest"));
174 }
175
176 #[test]
177 fn vitest_prefix_matches() {
178 assert!(is_known_tooling_dependency("@vitest/coverage-v8"));
179 assert!(is_known_tooling_dependency("@vitest/ui"));
180 }
181
182 #[test]
183 fn eslint_prefix_matches() {
184 assert!(is_known_tooling_dependency("eslint"));
185 assert!(is_known_tooling_dependency("eslint-plugin-react"));
186 assert!(is_known_tooling_dependency("eslint-config-next"));
187 }
188
189 #[test]
190 fn biomejs_prefix_matches() {
191 assert!(is_known_tooling_dependency("@biomejs/biome"));
192 }
193
194 #[test]
197 fn exact_typescript_matches() {
198 assert!(is_known_tooling_dependency("typescript"));
199 }
200
201 #[test]
202 fn exact_prettier_matches() {
203 assert!(is_known_tooling_dependency("prettier"));
204 }
205
206 #[test]
207 fn exact_vitest_matches() {
208 assert!(is_known_tooling_dependency("vitest"));
209 }
210
211 #[test]
212 fn exact_jest_matches() {
213 assert!(is_known_tooling_dependency("jest"));
214 }
215
216 #[test]
217 fn exact_vite_matches() {
218 assert!(is_known_tooling_dependency("vite"));
219 }
220
221 #[test]
222 fn exact_esbuild_matches() {
223 assert!(is_known_tooling_dependency("esbuild"));
224 }
225
226 #[test]
227 fn exact_tsup_matches() {
228 assert!(is_known_tooling_dependency("tsup"));
229 }
230
231 #[test]
232 fn exact_turbo_matches() {
233 assert!(is_known_tooling_dependency("turbo"));
234 }
235
236 #[test]
239 fn common_runtime_deps_not_tooling() {
240 assert!(!is_known_tooling_dependency("react"));
241 assert!(!is_known_tooling_dependency("react-dom"));
242 assert!(!is_known_tooling_dependency("express"));
243 assert!(!is_known_tooling_dependency("lodash"));
244 assert!(!is_known_tooling_dependency("next"));
245 assert!(!is_known_tooling_dependency("vue"));
246 assert!(!is_known_tooling_dependency("axios"));
247 }
248
249 #[test]
250 fn empty_string_not_tooling() {
251 assert!(!is_known_tooling_dependency(""));
252 }
253
254 #[test]
255 fn near_miss_not_tooling() {
256 assert!(!is_known_tooling_dependency("type-fest"));
258 assert!(!is_known_tooling_dependency("typestyle"));
259 assert!(!is_known_tooling_dependency("prettier-bytes")); }
264
265 #[test]
266 fn sass_variants_are_tooling() {
267 assert!(is_known_tooling_dependency("sass"));
268 assert!(is_known_tooling_dependency("sass-embedded"));
269 }
270
271 #[test]
272 fn prettier_plugins_are_tooling() {
273 assert!(is_known_tooling_dependency(
274 "@ianvs/prettier-plugin-sort-imports"
275 ));
276 assert!(is_known_tooling_dependency("prettier-plugin-tailwindcss"));
277 }
278}