@synergyerp/frontend-standards 1.2.0 → 1.3.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/.github/workflows/ci-template.yml +12 -4
- package/.husky/pre-commit +3 -0
- package/.husky/pre-push +3 -0
- package/eslint.config.js +24 -12
- package/package.json +1 -1
- package/scripts/detect-no-verify.sh +62 -0
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
# Consumer repos should USE this as a reference, not directly call it.
|
|
5
5
|
# The actual CI is triggered by the consumer repo's own .github/workflows/ci.yml
|
|
6
6
|
# which installs @synergyerp/frontend-standards and runs the same commands.
|
|
7
|
+
#
|
|
8
|
+
# ANTI-BYPASS DESIGN: Local git hooks (Husky) can be skipped with --no-verify.
|
|
9
|
+
# This CI pipeline is the SERVER-SIDE enforcement layer that cannot be bypassed.
|
|
10
|
+
# Every PR is re-validated here regardless of what happened locally.
|
|
7
11
|
|
|
8
12
|
name: CI Pipeline (Template)
|
|
9
13
|
|
|
@@ -45,16 +49,20 @@ jobs:
|
|
|
45
49
|
- name: Install dependencies
|
|
46
50
|
run: pnpm install --frozen-lockfile
|
|
47
51
|
|
|
52
|
+
# SERVER-SIDE ANTI-BYPASS: Validates ALL commit messages in this PR,
|
|
53
|
+
# catching any commits that were made with --no-verify locally.
|
|
54
|
+
# This step runs unconditionally and will fail if any commit in the PR
|
|
55
|
+
# does not meet the conventional commit standard.
|
|
56
|
+
- name: Validate Commit Messages (--no-verify anti-bypass)
|
|
57
|
+
if: github.event_name == 'pull_request'
|
|
58
|
+
run: pnpm exec commitlint --from origin/${{ github.base_ref }} --to HEAD
|
|
59
|
+
|
|
48
60
|
- name: Lint (ESLint + boundaries + no-internal-modules)
|
|
49
61
|
run: pnpm lint
|
|
50
62
|
|
|
51
63
|
- name: Check Modularization (domain structure + barrels)
|
|
52
64
|
run: pnpm check-modularization
|
|
53
65
|
|
|
54
|
-
- name: Validate Commit Messages (anti-bypass for --no-verify)
|
|
55
|
-
if: github.event_name == 'pull_request'
|
|
56
|
-
run: pnpm exec commitlint --from origin/${{ github.base_ref }} --to HEAD
|
|
57
|
-
|
|
58
66
|
- name: Type Check
|
|
59
67
|
run: pnpm check-types
|
|
60
68
|
|
package/.husky/pre-commit
CHANGED
package/.husky/pre-push
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env sh
|
|
2
2
|
. "$(dirname -- "$0")/_/husky.sh"
|
|
3
3
|
|
|
4
|
+
# Detect --no-verify bypass patterns
|
|
5
|
+
sh "$(dirname -- "$0")/../scripts/detect-no-verify.sh"
|
|
6
|
+
|
|
4
7
|
echo "🚀 Running pre-push quality checks..."
|
|
5
8
|
pnpm lint && pnpm check-modularization && pnpm check-types && pnpm test:ci
|
package/eslint.config.js
CHANGED
|
@@ -158,23 +158,19 @@ export default tseslint.config(
|
|
|
158
158
|
},
|
|
159
159
|
{
|
|
160
160
|
selector: "VariableDeclarator[id.name='temp']",
|
|
161
|
-
message:
|
|
162
|
-
"Variable name 'temp' is banned. Use a descriptive name like 'formattedDate'.",
|
|
161
|
+
message: "Variable name 'temp' is banned. Use a descriptive name like 'formattedDate'.",
|
|
163
162
|
},
|
|
164
163
|
{
|
|
165
164
|
selector: "VariableDeclarator[id.name='arr']",
|
|
166
|
-
message:
|
|
167
|
-
"Variable name 'arr' is banned. Use a descriptive name like 'permissions'.",
|
|
165
|
+
message: "Variable name 'arr' is banned. Use a descriptive name like 'permissions'.",
|
|
168
166
|
},
|
|
169
167
|
{
|
|
170
168
|
selector: "VariableDeclarator[id.name='obj']",
|
|
171
|
-
message:
|
|
172
|
-
"Variable name 'obj' is banned. Use a descriptive name like 'config'.",
|
|
169
|
+
message: "Variable name 'obj' is banned. Use a descriptive name like 'config'.",
|
|
173
170
|
},
|
|
174
171
|
{
|
|
175
172
|
selector: "VariableDeclarator[id.name='str']",
|
|
176
|
-
message:
|
|
177
|
-
"Variable name 'str' is banned. Use a descriptive name like 'message'.",
|
|
173
|
+
message: "Variable name 'str' is banned. Use a descriptive name like 'message'.",
|
|
178
174
|
},
|
|
179
175
|
{
|
|
180
176
|
selector: "VariableDeclarator[id.name='result']",
|
|
@@ -183,14 +179,29 @@ export default tseslint.config(
|
|
|
183
179
|
},
|
|
184
180
|
{
|
|
185
181
|
selector: "VariableDeclarator[id.name='myVar']",
|
|
182
|
+
message: "Variable name 'myVar' is banned. Use a descriptive name like 'username'.",
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
selector: "FunctionDeclaration[id.name='handle'], FunctionExpression[id.name='handle']",
|
|
186
186
|
message:
|
|
187
|
-
"
|
|
187
|
+
"Function name 'handle' is banned. Use a descriptive name like 'handleFormSubmit'.",
|
|
188
188
|
},
|
|
189
|
+
// ===== PREVENT _-PREFIXED SINGLE-LETTER NAMES (bypassing id-length) =====
|
|
189
190
|
{
|
|
190
191
|
selector:
|
|
191
|
-
|
|
192
|
+
'VariableDeclarator[id.name=/^_[a-z]$/], FunctionDeclaration[id.name=/^_[a-z]$/], FunctionExpression[id.name=/^_[a-z]$/]',
|
|
192
193
|
message:
|
|
193
|
-
"
|
|
194
|
+
"Do not use '_'-prefixed single-letter names (e.g. '_d', '_e', '_q'). Use meaningful names like 'date', 'employee', 'query'.",
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
selector: 'ArrowFunctionExpression > Identifier[name=/^_[a-z]$/]:first-child',
|
|
198
|
+
message:
|
|
199
|
+
"Do not use '_'-prefixed single-letter parameter names (e.g. '_s', '_r'). Use meaningful names like 'state', 'row'.",
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
selector:
|
|
203
|
+
'FunctionDeclaration > Identifier[name=/^_[a-z]$/]:first-child, FunctionExpression > Identifier[name=/^_[a-z]$/]:first-child',
|
|
204
|
+
message: "Do not use '_'-prefixed single-letter parameter names. Use meaningful names.",
|
|
194
205
|
},
|
|
195
206
|
],
|
|
196
207
|
|
|
@@ -234,8 +245,9 @@ export default tseslint.config(
|
|
|
234
245
|
'@typescript-eslint/no-unused-vars': [
|
|
235
246
|
'error',
|
|
236
247
|
{
|
|
237
|
-
varsIgnorePattern: '^_',
|
|
238
248
|
argsIgnorePattern: '^_',
|
|
249
|
+
destructuredArrayIgnorePattern: '^_',
|
|
250
|
+
ignoreRestSiblings: true,
|
|
239
251
|
},
|
|
240
252
|
],
|
|
241
253
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synergyerp/frontend-standards",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "SynergyERP frontend standards — ESLint, Prettier, commitlint, Husky, Vitest, TypeScript configs, modularization enforcement, and PR templates.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
# ============================================================
|
|
3
|
+
# detect-no-verify.sh
|
|
4
|
+
#
|
|
5
|
+
# PURPOSE: Warn developers when --no-verify aliases / config
|
|
6
|
+
# are detected. This script is run in pre-commit and pre-push
|
|
7
|
+
# hooks. It does NOT block git itself (which cannot be done at
|
|
8
|
+
# the OS level), but it:
|
|
9
|
+
# 1. Detects known --no-verify aliases in global/local git config
|
|
10
|
+
# 2. Logs a dated violation entry to .git/no-verify-violations.log
|
|
11
|
+
# 3. Exits non-zero so the hook chain fails loudly
|
|
12
|
+
#
|
|
13
|
+
# The CI pipeline independently re-validates all commit messages
|
|
14
|
+
# via commitlint (see .github/workflows/ci-template.yml), which
|
|
15
|
+
# is the actual server-side enforcement that --no-verify cannot
|
|
16
|
+
# bypass.
|
|
17
|
+
# ============================================================
|
|
18
|
+
|
|
19
|
+
set -e
|
|
20
|
+
|
|
21
|
+
VIOLATIONS=0
|
|
22
|
+
|
|
23
|
+
echo ""
|
|
24
|
+
echo "🛡️ Checking for --no-verify bypass patterns..."
|
|
25
|
+
|
|
26
|
+
# 1. Scan all git aliases in local + global config
|
|
27
|
+
ALL_ALIASES=$(git config --list 2>/dev/null | grep '^alias\.' || true)
|
|
28
|
+
|
|
29
|
+
if echo "$ALL_ALIASES" | grep -qi 'no-verify\|no.verify'; then
|
|
30
|
+
echo ""
|
|
31
|
+
echo "❌ ERROR: A git alias containing --no-verify was found in your git config!"
|
|
32
|
+
echo ""
|
|
33
|
+
echo "$ALL_ALIASES" | grep -i 'no-verify\|no.verify'
|
|
34
|
+
echo ""
|
|
35
|
+
echo " Please remove this alias. The standards require all commits to pass hooks."
|
|
36
|
+
echo " Run: git config --global --unset alias.<name>"
|
|
37
|
+
VIOLATIONS=$((VIOLATIONS + 1))
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# 2. Check for HUSKY=0 environment variable (bypasses husky hooks entirely)
|
|
41
|
+
if [ "${HUSKY}" = "0" ]; then
|
|
42
|
+
echo ""
|
|
43
|
+
echo "❌ ERROR: HUSKY=0 is set — this bypasses ALL Husky hooks!"
|
|
44
|
+
echo " Unset HUSKY or remove it from your shell profile."
|
|
45
|
+
VIOLATIONS=$((VIOLATIONS + 1))
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# 3. Log violations to .git/no-verify-violations.log for auditability
|
|
49
|
+
if [ $VIOLATIONS -gt 0 ]; then
|
|
50
|
+
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
51
|
+
LOG_FILE="$(git rev-parse --git-dir)/no-verify-violations.log"
|
|
52
|
+
echo "$TIMESTAMP user=$(git config user.email 2>/dev/null || echo unknown) violations=$VIOLATIONS" >> "$LOG_FILE"
|
|
53
|
+
echo ""
|
|
54
|
+
echo " ☝️ A record of this violation has been written to .git/no-verify-violations.log"
|
|
55
|
+
echo " ☝️ Note: even if you bypass this hook, the CI pipeline will re-run commitlint"
|
|
56
|
+
echo " on every PR and will reject commits that skipped required validation."
|
|
57
|
+
echo ""
|
|
58
|
+
exit 1
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
echo "✅ No --no-verify bypass patterns detected."
|
|
62
|
+
echo ""
|