@zairakai/js-dev-tools 1.0.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.
Files changed (69) hide show
  1. package/.editorconfig +86 -0
  2. package/.gitlab/ci/pipeline-js-app.yml +75 -0
  3. package/.gitlab/ci/pipeline-js-package.yml +360 -0
  4. package/LICENSE +21 -0
  5. package/README.md +206 -0
  6. package/config/.markdownlint.json +7 -0
  7. package/config/.markdownlintignore +5 -0
  8. package/config/.prettierignore +11 -0
  9. package/config/.stylelintignore +7 -0
  10. package/config/eslint.config.js +198 -0
  11. package/config/knip.config.js +40 -0
  12. package/config/prettier.config.js +121 -0
  13. package/config/stylelint.config.js +56 -0
  14. package/config/tsconfig.base.json +20 -0
  15. package/config/vitest.config.js +25 -0
  16. package/index.js +24 -0
  17. package/package.json +148 -0
  18. package/scripts/build.sh +58 -0
  19. package/scripts/ci-quality.sh +51 -0
  20. package/scripts/config.sh +254 -0
  21. package/scripts/doctor.sh +74 -0
  22. package/scripts/eslint-fix.sh +38 -0
  23. package/scripts/eslint.sh +49 -0
  24. package/scripts/install-bats.sh +227 -0
  25. package/scripts/install-hooks.sh +167 -0
  26. package/scripts/install-markdownlint.sh +31 -0
  27. package/scripts/install-shellcheck.sh +232 -0
  28. package/scripts/knip.sh +40 -0
  29. package/scripts/markdownlint-fix.sh +8 -0
  30. package/scripts/markdownlint.sh +84 -0
  31. package/scripts/outdated.sh +70 -0
  32. package/scripts/prettier-fix.sh +52 -0
  33. package/scripts/prettier.sh +53 -0
  34. package/scripts/setup-project.sh +816 -0
  35. package/scripts/stylelint-fix.sh +64 -0
  36. package/scripts/stylelint.sh +66 -0
  37. package/scripts/test.sh +40 -0
  38. package/scripts/typecheck.sh +41 -0
  39. package/scripts/validate-shellcheck.sh +70 -0
  40. package/stubs/githooks/commit-msg +34 -0
  41. package/stubs/githooks/pre-commit +58 -0
  42. package/stubs/githooks/pre-push +57 -0
  43. package/stubs/githooks/prepare-commit-msg +39 -0
  44. package/stubs/gitlab-ci/gitlab-ci.yml.stub +18 -0
  45. package/stubs/gitlab-ci/gitlab-pipeline-js-app.yml.stub +16 -0
  46. package/stubs/governance/CODE_OF_CONDUCT.md.stub +8 -0
  47. package/stubs/governance/CONTRIBUTING.md.stub +39 -0
  48. package/stubs/governance/SECURITY.md.stub +41 -0
  49. package/stubs/quality/eslint.config.js.stub +18 -0
  50. package/stubs/quality/knip.config.js.stub +14 -0
  51. package/stubs/style/prettier.config.js.stub +16 -0
  52. package/stubs/style/stylelint.config.js.stub +17 -0
  53. package/stubs/testing/vitest.config.js.stub +18 -0
  54. package/stubs/typescript/tsconfig.json.stub +10 -0
  55. package/tools/make/bats.mk +49 -0
  56. package/tools/make/code-style.mk +20 -0
  57. package/tools/make/core.mk +56 -0
  58. package/tools/make/help.mk +32 -0
  59. package/tools/make/knip.mk +7 -0
  60. package/tools/make/markdownlint.mk +17 -0
  61. package/tools/make/quality.mk +19 -0
  62. package/tools/make/shellcheck.mk +14 -0
  63. package/tools/make/stylelint.mk +11 -0
  64. package/tools/make/test.mk +19 -0
  65. package/tools/make/typescript.mk +10 -0
  66. package/tools/make/utils.mk +44 -0
  67. package/tools/make/variables.mk +42 -0
  68. package/tools/scripts/git-cleanup.sh +53 -0
  69. package/tools/scripts/git-update.sh +37 -0
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Default Vitest configuration for @zairakai packages.
3
+ * Provides sensible defaults for TypeScript projects.
4
+ *
5
+ * To customize, publish this file to your project:
6
+ * bash node_modules/@zairakai/js-dev-tools/scripts/setup-project.sh --publish=vitest
7
+ *
8
+ * The published config (config/dev-tools/vitest.config.js) can extend this
9
+ * base config and add project-specific settings (Vue plugin, jsdom, etc.).
10
+ */
11
+
12
+ import { defineConfig } from 'vitest/config'
13
+
14
+ export default defineConfig({
15
+ test: {
16
+ globals: true,
17
+ environment: 'node',
18
+ coverage: {
19
+ provider: 'v8',
20
+ reporter: ['text', 'lcov', 'html', 'cobertura'],
21
+ reportsDirectory: 'build/coverage',
22
+ exclude: ['node_modules/**', 'dist/**', 'build/**', '**/*.config.*', '**/*.d.ts'],
23
+ },
24
+ },
25
+ })
package/index.js ADDED
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @zairakai/js-dev-tools
3
+ * Development toolkit - ESLint, Prettier, Stylelint, TypeScript, and Vitest.
4
+ */
5
+
6
+ import eslint from './config/eslint.config.js'
7
+ import knip from './config/knip.config.js'
8
+ import prettier from './config/prettier.config.js'
9
+ import stylelint from './config/stylelint.config.js'
10
+ import tsconfig from './config/tsconfig.base.json' with { type: 'json' }
11
+ import vitest from './config/vitest.config.js'
12
+
13
+ // Named exports
14
+ export { eslint, knip, prettier, stylelint, tsconfig, vitest }
15
+
16
+ // Named paths for consumers
17
+ export const configs = {
18
+ eslint: '@zairakai/js-dev-tools/config/eslint.config.js',
19
+ prettier: '@zairakai/js-dev-tools/config/prettier.config.js',
20
+ stylelint: '@zairakai/js-dev-tools/config/stylelint.config.js',
21
+ vitest: '@zairakai/js-dev-tools/config/vitest.config.js',
22
+ knip: '@zairakai/js-dev-tools/config/knip.config.js',
23
+ tsconfig: '@zairakai/js-dev-tools/config/tsconfig.base.json',
24
+ }
package/package.json ADDED
@@ -0,0 +1,148 @@
1
+ {
2
+ "name": "@zairakai/js-dev-tools",
3
+ "version": "1.0.0",
4
+ "description": "The unified and centralized development toolkit for JavaScript/TypeScript projects - ESLint, Prettier, Stylelint, Knip, Vitest, Git Hooks, and GitLab CI pipeline templates",
5
+ "keywords": [
6
+ "dev-tools",
7
+ "toolkit",
8
+ "unified",
9
+ "centralized",
10
+ "makefile",
11
+ "git-hooks",
12
+ "gitlab-ci",
13
+ "eslint",
14
+ "prettier",
15
+ "stylelint",
16
+ "vitest",
17
+ "knip",
18
+ "typescript"
19
+ ],
20
+ "homepage": "https://gitlab.com/zairakai/npm-packages/js-dev-tools",
21
+ "bugs": {
22
+ "url": "https://gitlab.com/zairakai/npm-packages/js-dev-tools/-/issues",
23
+ "email": "contact-project+zairakai-npm-packages-js-dev-tools-80188322-issue-@incoming.gitlab.com"
24
+ },
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://gitlab.com/zairakai/npm-packages/js-dev-tools.git"
28
+ },
29
+ "funding": [
30
+ {
31
+ "type": "patreon",
32
+ "url": "https://www.patreon.com/c/zairakai"
33
+ },
34
+ {
35
+ "type": "twitch",
36
+ "url": "https://www.twitch.tv/zairakai"
37
+ }
38
+ ],
39
+ "license": "MIT",
40
+ "author": "Stanislas Poisson <stanislas.p@the-white-rabbits.fr> (https://the-white-rabbits.fr)",
41
+ "contributors": [
42
+ {
43
+ "name": "Stanislas Poisson",
44
+ "url": "https://gitlab.com/zairakai",
45
+ "role": "Maintainer"
46
+ }
47
+ ],
48
+ "type": "module",
49
+ "exports": {
50
+ ".": {
51
+ "import": "./index.js"
52
+ },
53
+ "./prettier": "./config/prettier.config.js",
54
+ "./eslint": "./config/eslint.config.js",
55
+ "./stylelint": "./config/stylelint.config.js",
56
+ "./vitest": "./config/vitest.config.js",
57
+ "./knip": "./config/knip.config.js",
58
+ "./tsconfig": "./config/tsconfig.base.json",
59
+ "./config/*": "./config/*"
60
+ },
61
+ "main": "index.js",
62
+ "files": [
63
+ ".gitlab/",
64
+ "config/",
65
+ "scripts/",
66
+ "stubs/",
67
+ "tools/",
68
+ "index.js",
69
+ ".editorconfig",
70
+ "LICENSE",
71
+ "README.md"
72
+ ],
73
+ "scripts": {
74
+ "eslint": "eslint --config config/eslint.config.js config/*.{js,ts}",
75
+ "eslint:fix": "eslint --config config/eslint.config.js config/*.{js,ts} --fix",
76
+ "postinstall": "bash ./scripts/setup-project.sh --silent || true",
77
+ "knip": "bash ./scripts/knip.sh",
78
+ "markdownlint": "markdownlint-cli2 --config config/.markdownlint.json --ignore-path config/.markdownlintignore '**/*.md' '#node_modules'",
79
+ "markdownlint:fix": "markdownlint-cli2 --fix --config config/.markdownlint.json --ignore-path config/.markdownlintignore '**/*.md' '#node_modules'",
80
+ "normalize": "make package-normalize",
81
+ "package:validate": "make package-validate",
82
+ "prettier": "prettier . --check --config ./config/prettier.config.js --ignore-path ./config/.prettierignore",
83
+ "prettier:fix": "prettier . --write --config ./config/prettier.config.js --ignore-path ./config/.prettierignore",
84
+ "setup": "bash ./scripts/setup-project.sh",
85
+ "stylelint": "stylelint --config config/stylelint.config.js --ignore-path config/.stylelintignore '**/*.scss'",
86
+ "stylelint:fix": "stylelint --config config/stylelint.config.js --ignore-path config/.stylelintignore '**/*.scss' --fix",
87
+ "test": "make test-all",
88
+ "validate": "make quality"
89
+ },
90
+ "dependencies": {
91
+ "@eslint/js": "^10.0.0",
92
+ "@prettier/plugin-php": "^0.24.0",
93
+ "@typescript-eslint/eslint-plugin": "^8.40.0",
94
+ "@typescript-eslint/parser": "^8.40.0",
95
+ "eslint": "^10.0.0",
96
+ "eslint-config-prettier": "^10.0.0",
97
+ "eslint-plugin-vue": "^10.0.0",
98
+ "globals": "^17.0.0",
99
+ "markdownlint-cli2": "^0.21.0",
100
+ "prettier": "^3.0.0",
101
+ "prettier-plugin-blade": "^2.1.0",
102
+ "prettier-plugin-organize-imports": "^4.0.0",
103
+ "stylelint": "^17.0.0",
104
+ "stylelint-config-html": "^1.1.0",
105
+ "stylelint-config-recommended-vue": "^1.5.0",
106
+ "stylelint-config-standard": "^40.0.0",
107
+ "stylelint-config-standard-scss": "^17.0.0",
108
+ "stylelint-order": "^8.0.0",
109
+ "stylelint-scss": "^7.0.0",
110
+ "vue-eslint-parser": "^10.0.0"
111
+ },
112
+ "devDependencies": {
113
+ "@eslint/compat": "^2.0.3",
114
+ "@vitest/coverage-v8": "^4.0.0",
115
+ "knip": "^5.85.0",
116
+ "sort-package-json": "^3.6.1",
117
+ "typescript": "^5.9.3",
118
+ "vitest": "^4.0.0",
119
+ "zod": "^4.0.0"
120
+ },
121
+ "peerDependencies": {
122
+ "eslint": "^10.0.0",
123
+ "prettier": "^3.0.0",
124
+ "stylelint": "^17.0.0",
125
+ "typedoc": "^0.28.0",
126
+ "zod": "^3.0.0 || ^4.0.0"
127
+ },
128
+ "peerDependenciesMeta": {
129
+ "stylelint": {
130
+ "optional": true
131
+ },
132
+ "typedoc": {
133
+ "optional": true
134
+ },
135
+ "zod": {
136
+ "optional": true
137
+ }
138
+ },
139
+ "engines": {
140
+ "node": ">=22.0.0"
141
+ },
142
+ "publishConfig": {
143
+ "access": "public"
144
+ },
145
+ "outdatedIgnore": [
146
+ "prettier-plugin-blade"
147
+ ]
148
+ }
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # TypeScript Build / Transpilation
4
+ # Compiles TypeScript to JavaScript for distribution.
5
+ #
6
+ # Supports (in order of preference):
7
+ # 1. tsup — fast, esbuild-based bundler (recommended for npm packages)
8
+ # 2. tsc — official TypeScript compiler
9
+ #
10
+ # Usage:
11
+ # bash scripts/build.sh
12
+ #
13
+ # Recommendation:
14
+ # Use tsup for npm packages: npm install --save-dev tsup
15
+ # Use tsc for apps: npm install --save-dev typescript
16
+ #
17
+
18
+ set -euo pipefail
19
+
20
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
21
+ # shellcheck disable=SC1091
22
+ source "${SCRIPT_DIR}/config.sh"
23
+
24
+ TSUP_BIN="${BIN_DIR}/tsup"
25
+ TSC_BIN="${BIN_DIR}/tsc"
26
+
27
+ log_header "TypeScript Build"
28
+
29
+ if [[ -f "$TSUP_BIN" ]]; then
30
+ log_info "Builder: tsup (fast, esbuild-based)"
31
+ if [[ -n "$TSUP_CONFIG" ]]; then
32
+ "$TSUP_BIN" --config "$TSUP_CONFIG"
33
+ else
34
+ "$TSUP_BIN"
35
+ fi
36
+ log_success "Build complete — output in dist/"
37
+
38
+ elif [[ -f "$TSC_BIN" ]]; then
39
+ log_info "Builder: tsc (official TypeScript compiler)"
40
+
41
+ if [[ ! -f "${PROJECT_ROOT}/tsconfig.json" ]]; then
42
+ log_error "No tsconfig.json found at project root"
43
+ log_info "Publish one with:"
44
+ log_info " bash node_modules/@zairakai/js-dev-tools/scripts/setup-project.sh --publish=tsconfig"
45
+ exit 1
46
+ fi
47
+
48
+ log_info "Config: tsconfig.json"
49
+ "$TSC_BIN"
50
+ log_success "Build complete"
51
+
52
+ else
53
+ log_error "No TypeScript builder found in node_modules/.bin/"
54
+ log_info "Install one of:"
55
+ log_info " npm install --save-dev tsup (recommended for npm packages)"
56
+ log_info " npm install --save-dev typescript (for apps or when you need full tsc control)"
57
+ exit 1
58
+ fi
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # CI Quality Aggregator
4
+ # Runs all quality checks (ESLint, Prettier, Stylelint, TypeScript)
5
+ # and reports all failures at once rather than stopping on the first error.
6
+ #
7
+ # Usage:
8
+ # bash scripts/ci-quality.sh
9
+ #
10
+
11
+ set -euo pipefail
12
+
13
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
14
+ # shellcheck disable=SC1091
15
+ source "$SCRIPT_DIR/config.sh"
16
+
17
+ log_header "Quality Checks"
18
+
19
+ init_error_counter
20
+
21
+ # 1. Documentation & Shell (Foundational)
22
+ run_check "Documentation (Markdownlint)" "bash '${SCRIPT_DIR}/markdownlint.sh'" || true
23
+ echo ""
24
+
25
+ run_check "Shell Scripts (ShellCheck)" "bash '${SCRIPT_DIR}/validate-shellcheck.sh'" || true
26
+ echo ""
27
+
28
+ # 2. Code Quality & Style (Language Specific)
29
+ run_check "Code Style (ESLint)" "bash '${SCRIPT_DIR}/eslint.sh'" || true
30
+ echo ""
31
+
32
+ run_check "Formatting (Prettier)" "bash '${SCRIPT_DIR}/prettier.sh'" || true
33
+ echo ""
34
+
35
+ run_check "CSS/SCSS (Stylelint)" "bash '${SCRIPT_DIR}/stylelint.sh'" || true
36
+ echo ""
37
+
38
+ # 3. Static Analysis (Optional, Project aware)
39
+ if [[ -f "${PROJECT_ROOT}/tsconfig.json" ]] && [[ -f "${BIN_DIR}/tsc" ]]; then
40
+ run_check "TypeScript (tsc --noEmit)" "bash '${SCRIPT_DIR}/typecheck.sh'" || true
41
+ echo ""
42
+ else
43
+ log_info "TypeScript: no tsconfig.json or tsc — skipping"
44
+ echo ""
45
+ fi
46
+
47
+ if exit_with_error_count "Quality Checks"; then
48
+ exit 0
49
+ else
50
+ exit 1
51
+ fi
@@ -0,0 +1,254 @@
1
+ #!/usr/bin/env bash
2
+ # Zairakai NPM Dev Tools - Central Configuration
3
+
4
+ set -euo pipefail
5
+
6
+ # ─── PATH DETECTION ───────────────────────────────────────────────────────────
7
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
+
9
+ # Vendor context: node_modules/@zairakai/js-dev-tools/scripts/
10
+ # Dev context: npm/dev-tools/scripts/
11
+ if [[ "$SCRIPT_DIR" =~ /node_modules/@zairakai/js-dev-tools/scripts ]]; then
12
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../../.." && pwd)"
13
+ DEV_TOOLS_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
14
+ else
15
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
16
+ DEV_TOOLS_ROOT="$PROJECT_ROOT"
17
+ fi
18
+
19
+ export PROJECT_ROOT
20
+ export DEV_TOOLS_ROOT
21
+
22
+ # ─── PACKAGE MANAGER DETECTION ────────────────────────────────────────────────
23
+ detect_package_manager() {
24
+ if [[ -f "$PROJECT_ROOT/yarn.lock" ]] || [[ -f "$PROJECT_ROOT/.yarnrc.yml" ]]; then
25
+ echo "yarn"
26
+ else
27
+ echo "npm"
28
+ fi
29
+ }
30
+
31
+ PM="$(detect_package_manager)"
32
+ export PM
33
+
34
+ # ─── PROJECT TYPE DETECTION ───────────────────────────────────────────────────
35
+ detect_project_type() {
36
+ if [[ -f "${PROJECT_ROOT}/artisan" ]] && [[ -d "${PROJECT_ROOT}/resources/js" ]]; then
37
+ echo "laravel-app"
38
+ return 0
39
+ fi
40
+ echo "npm-package"
41
+ }
42
+
43
+ PROJECT_TYPE="$(detect_project_type)"
44
+ export PROJECT_TYPE
45
+
46
+ # ─── BINARY PATHS ─────────────────────────────────────────────────────────────
47
+ BIN_DIR="${PROJECT_ROOT}/node_modules/.bin"
48
+ export ESLINT_BIN="${BIN_DIR}/eslint"
49
+ export PRETTIER_BIN="${BIN_DIR}/prettier"
50
+ export STYLELINT_BIN="${BIN_DIR}/stylelint"
51
+ export VITEST_BIN="${BIN_DIR}/vitest"
52
+ export MARKDOWNLINT_BIN="${BIN_DIR}/markdownlint-cli2"
53
+
54
+ # ─── CONFIG RESOLUTION ────────────────────────────────────────────────────────
55
+ # Cascade: project root → config/dev-tools/ → config/ → bundled default
56
+ resolve_config() {
57
+ local filename="$1"
58
+
59
+ # 1. Project root (full override)
60
+ if [[ -f "${PROJECT_ROOT}/${filename}" ]]; then
61
+ echo "${PROJECT_ROOT}/${filename}"
62
+ return 0
63
+ fi
64
+
65
+ # 2. config/dev-tools/ (published — can extend bundled default)
66
+ if [[ -f "${PROJECT_ROOT}/config/dev-tools/${filename}" ]]; then
67
+ echo "${PROJECT_ROOT}/config/dev-tools/${filename}"
68
+ return 0
69
+ fi
70
+
71
+ # 3. config/ (local usage or internal package structure)
72
+ if [[ -f "${PROJECT_ROOT}/config/${filename}" ]]; then
73
+ echo "${PROJECT_ROOT}/config/${filename}"
74
+ return 0
75
+ fi
76
+
77
+ # 4. Bundled default in dev-tools package (fallback when in node_modules)
78
+ if [[ -f "${DEV_TOOLS_ROOT}/config/${filename}" ]]; then
79
+ echo "${DEV_TOOLS_ROOT}/config/${filename}"
80
+ return 0
81
+ fi
82
+
83
+ echo ""
84
+ }
85
+
86
+ export -f resolve_config
87
+
88
+ # ─── COLORS ───────────────────────────────────────────────────────────────────
89
+ export RED='\033[0;31m'
90
+ export GREEN='\033[0;32m'
91
+ export YELLOW='\033[1;33m'
92
+ export BLUE='\033[0;34m'
93
+ export CYAN='\033[0;36m'
94
+ export MAGENTA='\033[0;35m'
95
+ export NC='\033[0m'
96
+
97
+ # ─── LOGGING ──────────────────────────────────────────────────────────────────
98
+ log_info() { echo -e "${CYAN}ℹ ${NC}$*"; }
99
+ log_success() { echo -e "${GREEN}✅ ${NC}$*"; }
100
+ log_warning() { echo -e "${YELLOW}⚠️ ${NC}$*"; }
101
+ log_error() { echo -e "${RED}❌ ${NC}$*" >&2; }
102
+ log_step() { echo -e "${BLUE}→${NC} $*"; }
103
+ log_header() { echo -e "\n${MAGENTA} $*${NC}\n${MAGENTA}════════════════${NC}\n"; }
104
+
105
+ export -f log_info
106
+ export -f log_success
107
+ export -f log_warning
108
+ export -f log_error
109
+ export -f log_step
110
+ export -f log_header
111
+
112
+ # ─── BINARY CHECKS ────────────────────────────────────────────────────────────
113
+ ensure_bin() {
114
+ local bin="$1"
115
+ local name="${2:-$(basename "$bin")}"
116
+ if [[ ! -f "$bin" ]]; then
117
+ log_error "${name} not found in node_modules/.bin/"
118
+ log_error "Run: ${PM} install"
119
+ return 1
120
+ fi
121
+ }
122
+ export -f ensure_bin
123
+
124
+ ensure_bin_optional() {
125
+ local bin="$1"
126
+ local name="${2:-$(basename "$bin")}"
127
+ if [[ ! -f "$bin" ]]; then
128
+ log_warning "${name} not installed — skipping (optional)"
129
+ return 1
130
+ fi
131
+ return 0
132
+ }
133
+ export -f ensure_bin_optional
134
+
135
+ # Check if files matching pattern exist
136
+ has_files() {
137
+ local pattern="$1"
138
+ # SC2086: unquoted intentionally — we need word splitting + glob expansion via nullglob
139
+ # shellcheck disable=SC2086
140
+ ( shopt -s nullglob; set -- $pattern; [ $# -gt 0 ] )
141
+ }
142
+ export -f has_files
143
+
144
+ # ─── ERROR COUNTER ────────────────────────────────────────────────────────────
145
+ ERROR_COUNT=0
146
+ export ERROR_COUNT
147
+ init_error_counter() { ERROR_COUNT=0; }
148
+ increment_error_counter() { ERROR_COUNT=$((ERROR_COUNT + 1)); }
149
+ get_error_count() { echo "$ERROR_COUNT"; }
150
+
151
+ exit_with_error_count() {
152
+ local name="${1:-Checks}"
153
+ if [[ $ERROR_COUNT -eq 0 ]]; then
154
+ log_header "✅ All ${name} Passed"
155
+ return 0
156
+ else
157
+ log_header "❌ ${ERROR_COUNT} ${name} Failed"
158
+ return 1
159
+ fi
160
+ }
161
+
162
+ export -f init_error_counter
163
+ export -f increment_error_counter
164
+ export -f get_error_count
165
+ export -f exit_with_error_count
166
+
167
+ run_check() {
168
+ local name="$1"
169
+ local cmd="$2"
170
+ log_info "Running: ${name}"
171
+ if eval "$cmd"; then
172
+ log_success "${name} passed"
173
+ else
174
+ log_error "${name} failed"
175
+ increment_error_counter
176
+ return 1
177
+ fi
178
+ }
179
+
180
+ # ─── BACKUP ──────────────────────────────────────────────────────────────────
181
+ BACKUP_DIR=""
182
+ backup_file() {
183
+ local file="$1"
184
+ local base="${2:-${PROJECT_ROOT}/.dev-tools-backup}"
185
+ [[ ! -f "$file" || -L "$file" ]] && return 1
186
+ if [[ -z "$BACKUP_DIR" ]]; then
187
+ BACKUP_DIR="${base}/$(date +%Y%m%d-%H%M%S)"
188
+ mkdir -p "$BACKUP_DIR"
189
+ fi
190
+ local rel="${file#"${PROJECT_ROOT}"/}"
191
+ local dest="${BACKUP_DIR}/${rel}"
192
+ mkdir -p "$(dirname "$dest")"
193
+ cp "$file" "$dest" 2>/dev/null
194
+ }
195
+
196
+ # ─── HELPERS ──────────────────────────────────────────────────────────────────
197
+ command_exists() { command -v "$1" >/dev/null 2>&1; }
198
+ ensure_dir() {
199
+ if [[ ! -d "$1" ]]; then
200
+ mkdir -p "$1"
201
+ log_step "Created directory: $1"
202
+ fi
203
+ }
204
+
205
+ # ─── FILE PROTECTION (SHA-256) ────────────────────────────────────────────────
206
+ file_hash() {
207
+ local file="$1"
208
+ if command_exists sha256sum; then
209
+ sha256sum "$file" | cut -d' ' -f1
210
+ elif command_exists shasum; then
211
+ shasum -a 256 "$file" | cut -d' ' -f1
212
+ else
213
+ echo ""
214
+ fi
215
+ }
216
+
217
+ # ─── ENVIRONMENT DETECTION ────────────────────────────────────────────────────
218
+ export IS_CI="${CI:-false}"
219
+ export IS_GITLAB_CI="${GITLAB_CI:-false}"
220
+ export IS_GITHUB_ACTIONS="${GITHUB_ACTIONS:-false}"
221
+
222
+ # ─── TOOL CONFIG RESOLUTION ───────────────────────────────────────────────────
223
+ # Pre-resolved at startup so individual scripts don't call resolve_config themselves.
224
+ ESLINT_CONFIG="$(resolve_config "eslint.config.js")"
225
+ export ESLINT_CONFIG
226
+
227
+ PRETTIER_CONFIG="$(resolve_config "prettier.config.js")"
228
+ PRETTIER_IGNORE="$(resolve_config ".prettierignore")"
229
+ export PRETTIER_CONFIG PRETTIER_IGNORE
230
+
231
+ STYLELINT_CONFIG="$(resolve_config "stylelint.config.js")"
232
+ STYLELINT_IGNORE="$(resolve_config ".stylelintignore")"
233
+ export STYLELINT_CONFIG STYLELINT_IGNORE
234
+
235
+ MARKDOWNLINT_CONFIG="$(resolve_config ".markdownlint.json")"
236
+ MARKDOWNLINT_IGNORE="$(resolve_config ".markdownlintignore")"
237
+ export MARKDOWNLINT_CONFIG MARKDOWNLINT_IGNORE
238
+
239
+ VITEST_CONFIG="$(resolve_config "vitest.config.js")"
240
+ export VITEST_CONFIG
241
+
242
+ KNIP_CONFIG="$(resolve_config "knip.config.js")"
243
+ export KNIP_CONFIG
244
+
245
+ TSUP_CONFIG="$(resolve_config "tsup.config.js")"
246
+ export TSUP_CONFIG
247
+
248
+ # ─── VALIDATION ───────────────────────────────────────────────────────────────
249
+ cd "$PROJECT_ROOT"
250
+
251
+ if [[ ! -d "${PROJECT_ROOT}/node_modules" ]]; then
252
+ log_error "Dependencies not installed. Run: ${PM} install"
253
+ exit 1
254
+ fi
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ # shellcheck disable=SC1091
6
+ source "$SCRIPT_DIR/config.sh"
7
+
8
+ log_header "Environment Diagnostics"
9
+
10
+ echo -e "${CYAN}Node.js Version:${NC}"
11
+ node --version
12
+
13
+ echo ""
14
+ echo -e "${CYAN}Package Manager:${NC}"
15
+ echo " → ${PM} $(${PM} --version)"
16
+
17
+ echo ""
18
+ echo -e "${CYAN}Project Type:${NC}"
19
+ echo " → ${PROJECT_TYPE}"
20
+
21
+ echo ""
22
+ echo -e "${CYAN}Available Tools:${NC}"
23
+ [[ -f "$ESLINT_BIN" ]] && echo " ✅ ESLint: $("$ESLINT_BIN" --version 2>/dev/null)" || echo " ❌ ESLint not found"
24
+ [[ -f "$PRETTIER_BIN" ]] && echo " ✅ Prettier: $("$PRETTIER_BIN" --version 2>/dev/null)" || echo " ❌ Prettier not found"
25
+ [[ -f "$STYLELINT_BIN" ]] && echo " ✅ Stylelint: $("$STYLELINT_BIN" --version 2>/dev/null)" || echo " ℹ️ Stylelint not installed (optional)"
26
+ [[ -f "$VITEST_BIN" ]] && echo " ✅ Vitest: $("$VITEST_BIN" --version 2>/dev/null)" || echo " ℹ️ Vitest not installed"
27
+ [[ -f "$MARKDOWNLINT_BIN" ]] && echo " ✅ Markdownlint: installed" || echo " ❌ Markdownlint not found"
28
+ [[ -f "${BIN_DIR}/knip" ]] && echo " ✅ Knip: installed" || echo " ℹ️ Knip not installed (optional)"
29
+ [[ -f "${BIN_DIR}/tsc" ]] && echo " ✅ TypeScript: $("${BIN_DIR}/tsc" --version 2>/dev/null)" || echo " ℹ️ TypeScript not installed (optional)"
30
+ [[ -f "${BIN_DIR}/tsup" ]] && echo " ✅ tsup: installed" || echo " ℹ️ tsup not installed (optional)"
31
+
32
+ echo ""
33
+ echo -e "${CYAN}CI/CD Detection:${NC}"
34
+ if [[ "$IS_CI" == "true" ]]; then
35
+ echo " ✅ Running in CI environment"
36
+ [[ "$IS_GITLAB_CI" == "true" ]] && echo " → Platform: GitLab CI"
37
+ [[ "$IS_GITHUB_ACTIONS" == "true" ]] && echo " → Platform: GitHub Actions"
38
+ else
39
+ echo " ℹ️ Local development environment"
40
+ fi
41
+
42
+ echo ""
43
+ echo -e "${CYAN}Configuration Files (resolved):${NC}"
44
+
45
+ show_config() {
46
+ local label="$1"
47
+ local value="$2"
48
+ if [[ -n "$value" ]] && [[ -f "$value" ]]; then
49
+ echo " ✅ ${label}: ${value#"$PROJECT_ROOT"/}"
50
+ else
51
+ echo " ℹ️ ${label}: Using defaults (no config file)"
52
+ fi
53
+ }
54
+
55
+ show_config "ESLint" "$ESLINT_CONFIG"
56
+ show_config "Prettier" "$PRETTIER_CONFIG"
57
+ show_config ".prettierignore" "$PRETTIER_IGNORE"
58
+ show_config "Stylelint" "$STYLELINT_CONFIG"
59
+ show_config ".stylelintignore" "$STYLELINT_IGNORE"
60
+ show_config "Markdownlint" "$MARKDOWNLINT_CONFIG"
61
+ show_config ".markdownlintignore" "$MARKDOWNLINT_IGNORE"
62
+ show_config "Vitest" "$VITEST_CONFIG"
63
+ show_config "Knip" "$KNIP_CONFIG"
64
+ show_config "tsup" "$TSUP_CONFIG"
65
+
66
+ echo ""
67
+ echo -e "${CYAN}Configuration Fallback Order (all tools):${NC}"
68
+ echo " 1. {file} (project root override)"
69
+ echo " 2. config/dev-tools/{file} (published — can extend bundled default)"
70
+ echo " 3. config/{file} (legacy or intermediate)"
71
+ echo " 4. node_modules/@zairakai/js-dev-tools/config/{file} (bundled default)"
72
+
73
+ echo ""
74
+ log_success "Diagnostics complete"
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ # shellcheck disable=SC1091
6
+ source "$SCRIPT_DIR/config.sh"
7
+
8
+ log_header "ESLint Fix"
9
+
10
+ ensure_bin "$ESLINT_BIN" "eslint" || exit 1
11
+
12
+ if [[ -n "$ESLINT_CONFIG" ]]; then
13
+ log_step "Using configuration: ${ESLINT_CONFIG#"$PROJECT_ROOT"/}"
14
+ fi
15
+
16
+ if [[ "$PROJECT_TYPE" == "laravel-app" ]]; then
17
+ LINT_TARGET="${LINT_TARGET:-resources/js/}"
18
+ else
19
+ LINT_TARGET="${LINT_TARGET:-src/}"
20
+ fi
21
+
22
+ log_step "Fixing: $LINT_TARGET"
23
+
24
+ # Skip gracefully if no matching files exist
25
+ if ! has_files "${PROJECT_ROOT}/${LINT_TARGET}**/*.{js,ts,vue,jsx,tsx}"; then
26
+ log_info "No JS/TS files found in ${LINT_TARGET} — skipping"
27
+ exit 0
28
+ fi
29
+
30
+ ESLINT_ARGS=(--fix)
31
+
32
+ if [[ -n "$ESLINT_CONFIG" ]] && [[ "$ESLINT_CONFIG" != "${PROJECT_ROOT}/eslint.config.js" ]]; then
33
+ ESLINT_ARGS+=(--config "$ESLINT_CONFIG")
34
+ fi
35
+
36
+ "$ESLINT_BIN" "${ESLINT_ARGS[@]}" "$LINT_TARGET"
37
+
38
+ log_success "ESLint fix applied"