@synergyerp/frontend-standards 1.2.0 → 1.3.1

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.
@@ -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
@@ -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 lint-staged..."
5
8
  pnpm exec lint-staged
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
@@ -125,15 +125,7 @@ export default tseslint.config(
125
125
  },
126
126
  rules: {
127
127
  // ===== NAMING (FRONTEND_STANDARDS.md Section 5.2) =====
128
- 'id-length': [
129
- 'error',
130
- {
131
- min: 2,
132
- max: 50,
133
- exceptions: ['i', 'j', 'k', '_', 'x', 'y', 'z'],
134
- properties: 'never',
135
- },
136
- ],
128
+ 'id-length': ['error', { min: 2, max: 50, properties: 'never' }],
137
129
  camelcase: [
138
130
  'error',
139
131
  {
@@ -158,23 +150,19 @@ export default tseslint.config(
158
150
  },
159
151
  {
160
152
  selector: "VariableDeclarator[id.name='temp']",
161
- message:
162
- "Variable name 'temp' is banned. Use a descriptive name like 'formattedDate'.",
153
+ message: "Variable name 'temp' is banned. Use a descriptive name like 'formattedDate'.",
163
154
  },
164
155
  {
165
156
  selector: "VariableDeclarator[id.name='arr']",
166
- message:
167
- "Variable name 'arr' is banned. Use a descriptive name like 'permissions'.",
157
+ message: "Variable name 'arr' is banned. Use a descriptive name like 'permissions'.",
168
158
  },
169
159
  {
170
160
  selector: "VariableDeclarator[id.name='obj']",
171
- message:
172
- "Variable name 'obj' is banned. Use a descriptive name like 'config'.",
161
+ message: "Variable name 'obj' is banned. Use a descriptive name like 'config'.",
173
162
  },
174
163
  {
175
164
  selector: "VariableDeclarator[id.name='str']",
176
- message:
177
- "Variable name 'str' is banned. Use a descriptive name like 'message'.",
165
+ message: "Variable name 'str' is banned. Use a descriptive name like 'message'.",
178
166
  },
179
167
  {
180
168
  selector: "VariableDeclarator[id.name='result']",
@@ -183,14 +171,29 @@ export default tseslint.config(
183
171
  },
184
172
  {
185
173
  selector: "VariableDeclarator[id.name='myVar']",
174
+ message: "Variable name 'myVar' is banned. Use a descriptive name like 'username'.",
175
+ },
176
+ {
177
+ selector: "FunctionDeclaration[id.name='handle'], FunctionExpression[id.name='handle']",
186
178
  message:
187
- "Variable name 'myVar' is banned. Use a descriptive name like 'username'.",
179
+ "Function name 'handle' is banned. Use a descriptive name like 'handleFormSubmit'.",
188
180
  },
181
+ // ===== PREVENT _-PREFIXED SINGLE-LETTER NAMES (bypassing id-length) =====
189
182
  {
190
183
  selector:
191
- "FunctionDeclaration[id.name='handle'], FunctionExpression[id.name='handle']",
184
+ 'VariableDeclarator[id.name=/^_[a-z]$/], FunctionDeclaration[id.name=/^_[a-z]$/], FunctionExpression[id.name=/^_[a-z]$/]',
192
185
  message:
193
- "Function name 'handle' is banned. Use a descriptive name like 'handleFormSubmit'.",
186
+ "Do not use '_'-prefixed single-letter names (e.g. '_d', '_e', '_q'). Use meaningful names like 'date', 'employee', 'query'.",
187
+ },
188
+ {
189
+ selector: 'ArrowFunctionExpression > Identifier[name=/^_[a-z]$/]:first-child',
190
+ message:
191
+ "Do not use '_'-prefixed single-letter parameter names (e.g. '_s', '_r'). Use meaningful names like 'state', 'row'.",
192
+ },
193
+ {
194
+ selector:
195
+ 'FunctionDeclaration > Identifier[name=/^_[a-z]$/]:first-child, FunctionExpression > Identifier[name=/^_[a-z]$/]:first-child',
196
+ message: "Do not use '_'-prefixed single-letter parameter names. Use meaningful names.",
194
197
  },
195
198
  ],
196
199
 
@@ -234,8 +237,9 @@ export default tseslint.config(
234
237
  '@typescript-eslint/no-unused-vars': [
235
238
  'error',
236
239
  {
237
- varsIgnorePattern: '^_',
238
240
  argsIgnorePattern: '^_',
241
+ destructuredArrayIgnorePattern: '^_',
242
+ ignoreRestSiblings: true,
239
243
  },
240
244
  ],
241
245
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synergyerp/frontend-standards",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
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 ""