@itcase/config 1.6.83 → 1.6.85
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 -0
- package/lint-staged/checkNoFileDependencies.js +130 -0
- package/lint-staged/index.js +10 -1
- package/lint-staged-ts/index.js +10 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -25,6 +25,7 @@ npm install --save-dev @itcase/config
|
|
|
25
25
|
- **Lint-staged** — запуск линтеров для измененных файлов
|
|
26
26
|
- `lint-staged/index.js` — базовая конфигурация
|
|
27
27
|
- `lint-staged-ts/index.js` — с проверкой типов TypeScript
|
|
28
|
+
- обе конфигурации блокируют коммит, если в `package.json` есть локальные зависимости `file:` / `link:`
|
|
28
29
|
|
|
29
30
|
- **PostCSS** — обработка CSS
|
|
30
31
|
- `postcss/index.js` — стандартная конфигурация
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { readdirSync, readFileSync } from 'node:fs'
|
|
2
|
+
import { join, relative } from 'node:path'
|
|
3
|
+
|
|
4
|
+
const FORBIDDEN_SPEC = /^(file:|link:)/i
|
|
5
|
+
|
|
6
|
+
const DEPENDENCY_KEYS = [
|
|
7
|
+
'dependencies',
|
|
8
|
+
'devDependencies',
|
|
9
|
+
'optionalDependencies',
|
|
10
|
+
'peerDependencies',
|
|
11
|
+
'overrides',
|
|
12
|
+
'resolutions',
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
const SKIP_DIRS = new Set([
|
|
16
|
+
'node_modules',
|
|
17
|
+
'dist',
|
|
18
|
+
'build',
|
|
19
|
+
'coverage',
|
|
20
|
+
'.git',
|
|
21
|
+
'.next',
|
|
22
|
+
'.turbo',
|
|
23
|
+
'storybook-static',
|
|
24
|
+
])
|
|
25
|
+
|
|
26
|
+
function shouldSkipDir(name) {
|
|
27
|
+
return SKIP_DIRS.has(name) || name.startsWith('.')
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function findPackageJsonFiles(directory, results = []) {
|
|
31
|
+
let entries
|
|
32
|
+
try {
|
|
33
|
+
entries = readdirSync(directory, { withFileTypes: true })
|
|
34
|
+
} catch {
|
|
35
|
+
return results
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
for (const entry of entries) {
|
|
39
|
+
const fullPath = join(directory, entry.name)
|
|
40
|
+
if (entry.isDirectory()) {
|
|
41
|
+
if (shouldSkipDir(entry.name)) continue
|
|
42
|
+
findPackageJsonFiles(fullPath, results)
|
|
43
|
+
continue
|
|
44
|
+
}
|
|
45
|
+
if (entry.isFile() && entry.name === 'package.json') {
|
|
46
|
+
results.push(fullPath)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return results
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function readPackageJson(file) {
|
|
54
|
+
let raw
|
|
55
|
+
try {
|
|
56
|
+
raw = readFileSync(file, 'utf8')
|
|
57
|
+
} catch {
|
|
58
|
+
return null
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
return JSON.parse(raw)
|
|
63
|
+
} catch {
|
|
64
|
+
return null
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function formatLocator(parts) {
|
|
69
|
+
const [section, ...keys] = parts
|
|
70
|
+
return section + keys.map((key) => `[${JSON.stringify(key)}]`).join('')
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function scanValue(value, parts, hits) {
|
|
74
|
+
if (typeof value === 'string') {
|
|
75
|
+
if (FORBIDDEN_SPEC.test(value.trim())) {
|
|
76
|
+
hits.push({ locator: formatLocator(parts), spec: value })
|
|
77
|
+
}
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return
|
|
82
|
+
|
|
83
|
+
for (const [key, nested] of Object.entries(value)) {
|
|
84
|
+
scanValue(nested, [...parts, key], hits)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function collectHits(pkg) {
|
|
89
|
+
const hits = []
|
|
90
|
+
for (const key of DEPENDENCY_KEYS) {
|
|
91
|
+
if (pkg[key] == null) continue
|
|
92
|
+
scanValue(pkg[key], [key], hits)
|
|
93
|
+
}
|
|
94
|
+
return hits
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const cliFiles = process.argv.slice(2)
|
|
98
|
+
const files = cliFiles.length ? cliFiles : findPackageJsonFiles(process.cwd())
|
|
99
|
+
|
|
100
|
+
const hitsByFile = []
|
|
101
|
+
|
|
102
|
+
for (const file of files) {
|
|
103
|
+
const pkg = readPackageJson(file)
|
|
104
|
+
if (!pkg || typeof pkg !== 'object' || Array.isArray(pkg)) continue
|
|
105
|
+
|
|
106
|
+
const hits = collectHits(pkg)
|
|
107
|
+
if (hits.length) {
|
|
108
|
+
hitsByFile.push({ file, hits })
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (!hitsByFile.length) {
|
|
113
|
+
process.exit(0)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const lines = [
|
|
117
|
+
'❌ Локальные зависимости file: / link: нельзя коммитить.',
|
|
118
|
+
' Замените их на версию из npm registry.',
|
|
119
|
+
'',
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
for (const { file, hits } of hitsByFile) {
|
|
123
|
+
lines.push(` ${relative(process.cwd(), file)}`)
|
|
124
|
+
for (const { locator, spec } of hits) {
|
|
125
|
+
lines.push(` ${locator}: ${spec}`)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
process.stderr.write(`${lines.join('\n')}\n`)
|
|
130
|
+
process.exit(1)
|
package/lint-staged/index.js
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
|
-
import { resolve } from 'node:path'
|
|
2
|
+
import { dirname, join, resolve } from 'node:path'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
3
4
|
|
|
5
|
+
const checkNoFileDependencies = join(
|
|
6
|
+
dirname(fileURLToPath(import.meta.url)),
|
|
7
|
+
'checkNoFileDependencies.js',
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
// eslint-disable-next-line import/no-default-export
|
|
4
11
|
export default {
|
|
12
|
+
// На любой staged-файл: если в package.json есть file:/link: — exit 1, коммит не пройдёт
|
|
13
|
+
'*': () => `node ${JSON.stringify(checkNoFileDependencies)}`,
|
|
5
14
|
'*.(js|jsx|ts|tsx)': (files) => {
|
|
6
15
|
const existing = files.filter((file) => existsSync(file))
|
|
7
16
|
if (!existing.length) return 'true'
|
package/lint-staged-ts/index.js
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
|
-
import { resolve } from 'node:path'
|
|
2
|
+
import { dirname, join, resolve } from 'node:path'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
3
4
|
|
|
5
|
+
const checkNoFileDependencies = join(
|
|
6
|
+
dirname(fileURLToPath(import.meta.url)),
|
|
7
|
+
'../lint-staged/checkNoFileDependencies.js',
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
// eslint-disable-next-line import/no-default-export
|
|
4
11
|
export default {
|
|
12
|
+
// На любой staged-файл: если в package.json есть file:/link: — exit 1, коммит не пройдёт
|
|
13
|
+
'*': () => `node ${JSON.stringify(checkNoFileDependencies)}`,
|
|
5
14
|
'*.(ts|tsx)': (files) => {
|
|
6
15
|
const existing = files.filter((file) => existsSync(file))
|
|
7
16
|
const tsFiles = existing.filter((file) => /\.(ts|tsx)$/.test(file))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@itcase/config",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.85",
|
|
4
4
|
"author": "ITCase",
|
|
5
5
|
"description": "ITCase Config",
|
|
6
6
|
"engines": {
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"@svgr/plugin-jsx": "^8.1.0",
|
|
64
64
|
"@svgr/plugin-svgo": "^8.1.0",
|
|
65
65
|
"@svgr/webpack": "^8.1.0",
|
|
66
|
-
"autoprefixer": "^10.
|
|
66
|
+
"autoprefixer": "^10.6.0",
|
|
67
67
|
"chokidar-cli": "^3.0.0",
|
|
68
68
|
"commitizen": "^4.3.2",
|
|
69
69
|
"conventional-changelog-conventionalcommits": "9.3.1",
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
"postcss-nested-ancestors": "^3.0.0",
|
|
96
96
|
"postcss-normalize": "^13.0.1",
|
|
97
97
|
"postcss-prepend-imports": "^1.0.1",
|
|
98
|
-
"postcss-preset-env": "^11.5.
|
|
98
|
+
"postcss-preset-env": "^11.5.3",
|
|
99
99
|
"postcss-pxtorem": "^6.1.0",
|
|
100
100
|
"postcss-sort-media-queries": "^6.7.1",
|
|
101
101
|
"postcss-unit": "^0.0.3",
|
|
@@ -112,11 +112,11 @@
|
|
|
112
112
|
"semantic-release-lerna": "^3.6.4"
|
|
113
113
|
},
|
|
114
114
|
"devDependencies": {
|
|
115
|
-
"@itcase/lint": "^1.1.
|
|
115
|
+
"@itcase/lint": "^1.1.125",
|
|
116
116
|
"eslint": "9.39.2",
|
|
117
117
|
"husky": "^9.1.7",
|
|
118
118
|
"inquirer": "^14.2.2",
|
|
119
|
-
"lint-staged": "^17.5.
|
|
119
|
+
"lint-staged": "^17.5.1",
|
|
120
120
|
"prettier": "^3.9.6",
|
|
121
121
|
"storybook": "^10.6.0",
|
|
122
122
|
"stylelint": "^17.15.0",
|