my-code-style 1.0.0 → 1.4.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/bin/init.cjs DELETED
@@ -1,476 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * my-code-style-init CLI
4
- *
5
- * Scaffolds lint/format/git config files into the current project.
6
- * Auto-detects ESLint version and CSS preprocessor for optimal config generation.
7
- *
8
- * Usage:
9
- * npx my-code-style-init
10
- * npx my-code-style-init --dry-run
11
- */
12
-
13
- const fs = require("fs")
14
- const path = require("path")
15
- const { execSync } = require("child_process")
16
-
17
- const PROJECT_ROOT = process.cwd()
18
- const PACKAGE_DIR = path.resolve(__dirname, "..")
19
-
20
- // --- Helpers ---
21
-
22
- function log(msg) {
23
- console.log(` ${msg}`)
24
- }
25
-
26
- function success(msg) {
27
- console.log(` ✓ ${msg}`)
28
- }
29
-
30
- function warn(msg) {
31
- console.log(` ⚠ ${msg}`)
32
- }
33
-
34
- function ensureDir(dirPath) {
35
- if (!fs.existsSync(dirPath)) {
36
- fs.mkdirSync(dirPath, { recursive: true })
37
- }
38
- }
39
-
40
- function writeFile(dest, content) {
41
- const destDir = path.dirname(dest)
42
- ensureDir(destDir)
43
- fs.writeFileSync(dest, content, "utf8")
44
- }
45
-
46
- function fileExists(relative) {
47
- return fs.existsSync(path.resolve(PROJECT_ROOT, relative))
48
- }
49
-
50
- function readTemplate(relativePath) {
51
- return fs.readFileSync(path.resolve(PACKAGE_DIR, relativePath), "utf8")
52
- }
53
-
54
- function getProjectPkg() {
55
- const pkgPath = path.resolve(PROJECT_ROOT, "package.json")
56
- if (!fs.existsSync(pkgPath)) return null
57
- return JSON.parse(fs.readFileSync(pkgPath, "utf8"))
58
- }
59
-
60
- function getDependencyVersion(pkg, depName) {
61
- return (pkg.dependencies && pkg.dependencies[depName])
62
- || (pkg.devDependencies && pkg.devDependencies[depName])
63
- || null
64
- }
65
-
66
- // --- Detection helpers ---
67
-
68
- /**
69
- * Detect ESLint major version from package.json
70
- * Returns 8, 9, or null (not installed)
71
- */
72
- function detectEslintVersion() {
73
- const pkg = getProjectPkg()
74
- if (!pkg) return null
75
- const version = getDependencyVersion(pkg, "eslint")
76
- if (!version) return null
77
- // Handle range specifiers like "^9.0.0", ">=8.0.0", "9.x"
78
- const match = version.match(/(\d+)/)
79
- return match ? parseInt(match[1], 10) : null
80
- }
81
-
82
- /**
83
- * Detect CSS preprocessor in use
84
- * Returns "scss", "less", or "none"
85
- */
86
- function detectCssPreprocessor() {
87
- const pkg = getProjectPkg()
88
- if (!pkg) return "scss"
89
- const allDeps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) }
90
-
91
- const hasSass = allDeps["sass"] || allDeps["node-sass"] || allDeps["sass-loader"]
92
- const hasLess = allDeps["less"] || allDeps["less-loader"]
93
-
94
- if (hasLess && !hasSass) return "less"
95
- if (hasSass) return "scss"
96
- if (hasLess) return "less"
97
-
98
- // Fallback: check for existing stylelint config
99
- if (fileExists(".stylelintrc.cjs") || fileExists(".stylelintrc.js")) {
100
- try {
101
- const content = fs.readFileSync(
102
- path.resolve(PROJECT_ROOT, ".stylelintrc.cjs"),
103
- "utf8"
104
- )
105
- if (content.includes("postcss-less")) return "less"
106
- } catch {}
107
- }
108
-
109
- return "scss" // default
110
- }
111
-
112
- /**
113
- * Detect if project is a uni-app project
114
- */
115
- function isUniAppProject() {
116
- const pkg = getProjectPkg()
117
- if (!pkg) return false
118
- const allDeps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) }
119
- return !!(allDeps["@dcloudio/uni-app"] || allDeps["uni-app"])
120
- }
121
-
122
- // --- Config templates ---
123
-
124
- function eslintrcContent(isUniApp) {
125
- const importPath = isUniApp
126
- ? "my-code-style/eslint/uniapp"
127
- : "my-code-style/eslint/vue3"
128
-
129
- return `// ESLint config — powered by my-code-style
130
- // https://www.npmjs.com/package/my-code-style
131
- const config = require("${importPath}")
132
-
133
- // 如果需要引入 unplugin-auto-import 生成的 globals,取消下面的注释:
134
- // config.extends = [...config.extends, "./.eslintrc-auto-import.json"]
135
-
136
- module.exports = config
137
- `
138
- }
139
-
140
- function eslintFlatConfigContent(isUniApp) {
141
- const importPath = isUniApp
142
- ? "my-code-style/eslint/flat/uniapp"
143
- : "my-code-style/eslint/flat/vue3"
144
-
145
- return `// ESLint Flat Config — powered by my-code-style
146
- // https://www.npmjs.com/package/my-code-style
147
- import uniappConfig from "${importPath}"
148
-
149
- export default uniappConfig
150
- `
151
- }
152
-
153
- function prettierrcContent() {
154
- return `// Prettier config — powered by my-code-style
155
- module.exports = require("my-code-style/prettier")
156
- `
157
- }
158
-
159
- function prettierignoreContent() {
160
- return readTemplate("src/prettierignore")
161
- }
162
-
163
- function stylelintrcContent(cssPreprocessor) {
164
- const importPath = cssPreprocessor === "less"
165
- ? "my-code-style/stylelint/less"
166
- : "my-code-style/stylelint"
167
-
168
- return `// Stylelint config — powered by my-code-style
169
- module.exports = require("${importPath}")
170
- `
171
- }
172
-
173
- function commitlintrcContent() {
174
- return `// Commitlint config — powered by my-code-style
175
- const base = require("my-code-style/commitlint")
176
- const { generateScopes, guessCurrentScope } = require("my-code-style/commitlint/scopes")
177
-
178
- const scopes = generateScopes("src")
179
- const scopeComplete = guessCurrentScope()
180
-
181
- module.exports = {
182
- ...base,
183
- prompt: {
184
- ...base.prompt,
185
- customScopesAlign: !scopeComplete ? "top" : "bottom",
186
- defaultScope: scopeComplete,
187
- scopes: [...scopes, "mock"],
188
- allowEmptyIssuePrefixs: false,
189
- allowCustomIssuePrefixs: false,
190
- },
191
- }
192
- `
193
- }
194
-
195
- function versionrcContent() {
196
- return `// standard-version config — powered by my-code-style
197
- module.exports = require("my-code-style/versionrc")
198
- `
199
- }
200
-
201
- function huskyCommitMsg() {
202
- return `#!/usr/bin/env sh
203
- . "$(dirname -- "$0")/_/husky.sh"
204
-
205
- npx --no-install commitlint --edit
206
- `
207
- }
208
-
209
- function huskyPreCommit() {
210
- return `#!/usr/bin/env sh
211
- . "$(dirname -- "$0")/_/husky.sh"
212
-
213
- npx --no-install -- lint-staged
214
- `
215
- }
216
-
217
- function editorconfigContent() {
218
- return readTemplate("src/editorconfig")
219
- }
220
-
221
- function gitattributesContent() {
222
- return readTemplate("src/gitattributes")
223
- }
224
-
225
- /**
226
- * Generate the lint-staged config based on detected CSS preprocessor
227
- */
228
- function getLintStagedConfig(cssPreprocessor) {
229
- const styleFiles = cssPreprocessor === "less"
230
- ? "**/*.{vue,css,less,html}"
231
- : cssPreprocessor === "none"
232
- ? "**/*.{vue,html}"
233
- : "**/*.{vue,css,scss,html}"
234
-
235
- return {
236
- "**/*.{html,vue,ts,cjs,json,md}": ["prettier --write"],
237
- "**/*.{vue,js,ts,jsx,tsx}": ["eslint --cache --fix"],
238
- [styleFiles]: ["stylelint --fix"],
239
- }
240
- }
241
-
242
- // --- Main ---
243
-
244
- function main() {
245
- const dryRun = process.argv.includes("--dry-run")
246
- const label = dryRun ? "[DRY RUN] " : ""
247
-
248
- console.log("")
249
- console.log(" my-code-style-init — 初始化项目配置")
250
- console.log("")
251
-
252
- if (dryRun) {
253
- warn("Dry run mode — no files will be written")
254
- console.log("")
255
- }
256
-
257
- // --- Detection phase ---
258
- const eslintVersion = detectEslintVersion()
259
- const cssPreprocessor = detectCssPreprocessor()
260
- const uniApp = isUniAppProject()
261
-
262
- // Determine ESLint format
263
- const useFlatConfig = eslintVersion === 9
264
- const eslintFormat = useFlatConfig ? "flat" : "eslintrc"
265
-
266
- log(`检测到 ESLint 版本: ${eslintVersion || "未知"} → 使用 ${eslintFormat} 格式`)
267
- log(`检测到 CSS 预处理器: ${cssPreprocessor}`)
268
- if (uniApp) log(`检测到 uni-app 项目`)
269
- console.log("")
270
-
271
- // --- Build file list based on detection ---
272
- const files = []
273
-
274
- if (useFlatConfig) {
275
- files.push({
276
- path: "eslint.config.ts",
277
- exists: fileExists("eslint.config.ts") || fileExists("eslint.config.js") || fileExists("eslint.config.mjs"),
278
- content: eslintFlatConfigContent(uniApp),
279
- })
280
- } else {
281
- files.push({
282
- path: ".eslintrc.cjs",
283
- exists: fileExists(".eslintrc.cjs"),
284
- content: eslintrcContent(uniApp),
285
- })
286
- }
287
-
288
- files.push({
289
- path: ".prettierrc.cjs",
290
- exists: fileExists(".prettierrc.cjs"),
291
- content: prettierrcContent(),
292
- })
293
-
294
- files.push({
295
- path: ".prettierignore",
296
- exists: fileExists(".prettierignore"),
297
- content: prettierignoreContent(),
298
- })
299
-
300
- // Stylelint: always generate, but note if no CSS preprocessor
301
- if (cssPreprocessor !== "none") {
302
- files.push({
303
- path: ".stylelintrc.cjs",
304
- exists: fileExists(".stylelintrc.cjs"),
305
- content: stylelintrcContent(cssPreprocessor),
306
- })
307
- } else {
308
- log("跳过 Stylelint 配置 (未检测到 CSS 预处理器)")
309
- }
310
-
311
- files.push({
312
- path: ".commitlintrc.cjs",
313
- exists: fileExists(".commitlintrc.cjs"),
314
- content: commitlintrcContent(),
315
- })
316
-
317
- files.push({
318
- path: ".versionrc.js",
319
- exists: fileExists(".versionrc.js"),
320
- content: versionrcContent(),
321
- })
322
-
323
- files.push({
324
- path: ".editorconfig",
325
- exists: fileExists(".editorconfig"),
326
- content: editorconfigContent(),
327
- })
328
-
329
- files.push({
330
- path: ".gitattributes",
331
- exists: fileExists(".gitattributes"),
332
- content: gitattributesContent(),
333
- })
334
-
335
- // Show what will be created/overwritten
336
- for (const f of files) {
337
- if (f.exists) {
338
- warn(`${label}覆盖 ${f.path}`)
339
- } else {
340
- success(`${label}创建 ${f.path}`)
341
- }
342
- }
343
-
344
- // Husky hooks
345
- const huskyDir = path.resolve(PROJECT_ROOT, ".husky")
346
- const hasHusky = fs.existsSync(huskyDir)
347
- if (!hasHusky) {
348
- success(`${label}创建 .husky/ 目录`)
349
- }
350
-
351
- const hooks = [
352
- { path: ".husky/commit-msg", content: huskyCommitMsg() },
353
- { path: ".husky/pre-commit", content: huskyPreCommit() },
354
- ]
355
-
356
- for (const h of hooks) {
357
- if (fileExists(h.path)) {
358
- warn(`${label}覆盖 ${h.path}`)
359
- } else {
360
- success(`${label}创建 ${h.path}`)
361
- }
362
- }
363
-
364
- if (dryRun) {
365
- console.log("")
366
- warn("Dry run 结束,未修改任何文件")
367
- console.log("")
368
- return
369
- }
370
-
371
- // Actually write files
372
- for (const f of files) {
373
- writeFile(f.path, f.content)
374
- }
375
-
376
- // Husky
377
- if (!hasHusky) {
378
- ensureDir(huskyDir)
379
- }
380
- for (const h of hooks) {
381
- writeFile(h.path, h.content)
382
- fs.chmodSync(path.resolve(PROJECT_ROOT, h.path), 0o755)
383
- }
384
-
385
- // package.json scripts + lint-staged
386
- modifyPackageJson({
387
- scripts: {
388
- prepare: "husky install",
389
- release: "standard-version",
390
- cz: "czg",
391
- },
392
- "lint-staged": getLintStagedConfig(cssPreprocessor),
393
- })
394
- success("更新 package.json (scripts + lint-staged)")
395
-
396
- // Check for missing peerDependencies
397
- checkPeerDeps({ useFlatConfig, cssPreprocessor })
398
-
399
- console.log("")
400
- success("配置初始化完成!")
401
- console.log("")
402
- console.log(" 下一步:")
403
- console.log(" 1. 确保已安装 peerDependencies:")
404
- console.log(" pnpm add -D my-code-style")
405
- if (useFlatConfig) {
406
- console.log(" 2. Flat Config 需要的额外依赖:")
407
- console.log(" pnpm add -D typescript-eslint globals eslint-plugin-import-x @eslint/js")
408
- }
409
- console.log(" 3. 初始化 husky:")
410
- console.log(" pnpm prepare")
411
- console.log(" 4. 使用 czg 提交 commit:")
412
- console.log(" pnpm cz")
413
- console.log("")
414
- }
415
-
416
- function modifyPackageJson(updates) {
417
- const pkgPath = path.resolve(PROJECT_ROOT, "package.json")
418
- let pkg = {}
419
- if (fileExists("package.json")) {
420
- pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"))
421
- }
422
-
423
- // Merge scripts
424
- if (updates.scripts) {
425
- pkg.scripts = { ...pkg.scripts, ...updates.scripts }
426
- }
427
-
428
- // Merge lint-staged
429
- if (updates["lint-staged"]) {
430
- pkg["lint-staged"] = { ...pkg["lint-staged"], ...updates["lint-staged"] }
431
- }
432
-
433
- fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 4) + "\n", "utf8")
434
- }
435
-
436
- function checkPeerDeps({ useFlatConfig = false, cssPreprocessor = "scss" } = {}) {
437
- const baseDeps = [
438
- "eslint",
439
- "prettier",
440
- "@commitlint/cli",
441
- "husky",
442
- "lint-staged",
443
- "czg",
444
- "standard-version",
445
- ]
446
-
447
- const flatDeps = useFlatConfig
448
- ? ["typescript-eslint", "globals", "eslint-plugin-import-x", "@eslint/js"]
449
- : []
450
-
451
- const cssDeps = cssPreprocessor === "scss"
452
- ? ["stylelint", "postcss-scss"]
453
- : cssPreprocessor === "less"
454
- ? ["stylelint", "postcss-less"]
455
- : []
456
-
457
- const allPeerDeps = [...baseDeps, ...flatDeps, ...cssDeps]
458
-
459
- const pkgPath = path.resolve(PROJECT_ROOT, "package.json")
460
- if (!fileExists("package.json")) return
461
-
462
- const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"))
463
- const allDeps = {
464
- ...(pkg.dependencies || {}),
465
- ...(pkg.devDependencies || {}),
466
- }
467
-
468
- const missing = allPeerDeps.filter((dep) => !allDeps[dep])
469
- if (missing.length > 0) {
470
- console.log("")
471
- warn("以下 peerDependencies 未安装,建议安装:")
472
- warn(`pnpm add -D ${missing.join(" ")}`)
473
- }
474
- }
475
-
476
- main()