@zairakai/dev-tools 1.0.11
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/.editorconfig +86 -0
- package/.gitlab/ci/pipeline-js.yml +189 -0
- package/.gitlab/ci/pipeline-npm-package.yml +353 -0
- package/LICENSE +21 -0
- package/README.md +162 -0
- package/config/.markdownlint.json +7 -0
- package/config/.markdownlintignore +5 -0
- package/config/.prettierignore +10 -0
- package/config/.stylelintignore +7 -0
- package/config/eslint.config.js +191 -0
- package/config/prettier.config.js +121 -0
- package/config/stylelint.config.js +56 -0
- package/config/tsconfig.base.json +20 -0
- package/config/vitest.config.js +25 -0
- package/index.js +22 -0
- package/package.json +137 -0
- package/scripts/build.sh +54 -0
- package/scripts/ci-quality.sh +47 -0
- package/scripts/config.sh +193 -0
- package/scripts/eslint-fix.sh +34 -0
- package/scripts/eslint.sh +46 -0
- package/scripts/install-bats.sh +227 -0
- package/scripts/install-shellcheck.sh +232 -0
- package/scripts/knip.sh +33 -0
- package/scripts/markdownlint-fix.sh +8 -0
- package/scripts/markdownlint.sh +43 -0
- package/scripts/prettier-fix.sh +33 -0
- package/scripts/prettier.sh +34 -0
- package/scripts/setup-project.sh +702 -0
- package/scripts/stylelint-fix.sh +39 -0
- package/scripts/stylelint.sh +47 -0
- package/scripts/test.sh +43 -0
- package/scripts/typecheck.sh +35 -0
- package/scripts/validate-shellcheck.sh +70 -0
- package/stubs/eslint.config.js.stub +18 -0
- package/stubs/gitlab-ci.yml.stub +18 -0
- package/stubs/gitlab-pipeline-js.yml.stub +16 -0
- package/stubs/prettier.config.js.stub +16 -0
- package/stubs/stylelint.config.js.stub +17 -0
- package/stubs/tsconfig.json.stub +10 -0
- package/stubs/vitest.config.js.stub +18 -0
- package/tools/make/bats.mk +49 -0
- package/tools/make/code-style.mk +29 -0
- package/tools/make/core.mk +50 -0
- package/tools/make/help.mk +32 -0
- package/tools/make/markdownlint.mk +17 -0
- package/tools/make/quality.mk +20 -0
- package/tools/make/shellcheck.mk +14 -0
- package/tools/make/stylelint.mk +0 -0
- package/tools/make/test.mk +19 -0
- package/tools/make/typescript.mk +14 -0
- package/tools/make/variables.mk +35 -0
|
@@ -0,0 +1,702 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Zairakai NPM Dev Tools - Project Setup Script
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# bash setup-project.sh # Normal setup (Makefile + .editorconfig + eslint baseline)
|
|
7
|
+
# bash setup-project.sh --publish # Publish all configs to config/dev-tools/
|
|
8
|
+
# bash setup-project.sh --publish=quality # Publish quality group (eslint)
|
|
9
|
+
# bash setup-project.sh --publish=style # Publish style group (prettier, stylelint, ignore files)
|
|
10
|
+
# bash setup-project.sh --publish=testing # Publish vitest config
|
|
11
|
+
# bash setup-project.sh --publish=gitlab-ci # Publish GitLab CI (auto-detects project type)
|
|
12
|
+
# bash setup-project.sh --publish=eslint # Publish specific config
|
|
13
|
+
# bash setup-project.sh --with-makefile # Also generate/inject Makefile
|
|
14
|
+
# bash setup-project.sh --force # Force overwrite existing files
|
|
15
|
+
# bash setup-project.sh --silent # Suppress output (errors only)
|
|
16
|
+
# bash setup-project.sh --help # Show this help
|
|
17
|
+
#
|
|
18
|
+
|
|
19
|
+
set -euo pipefail
|
|
20
|
+
|
|
21
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
22
|
+
# shellcheck disable=SC1091
|
|
23
|
+
source "${SCRIPT_DIR}/config.sh"
|
|
24
|
+
|
|
25
|
+
# ============================================================================
|
|
26
|
+
# Publishable configs registry
|
|
27
|
+
# Format: [key]="source_relative_to_dev_tools|target_relative_to_project|group"
|
|
28
|
+
# Note: gitlab-ci has a special handler (auto-detects project type) — not in this registry.
|
|
29
|
+
# ============================================================================
|
|
30
|
+
|
|
31
|
+
declare -A PUBLISHABLE=(
|
|
32
|
+
["eslint"]="stubs/eslint.config.js.stub|config/dev-tools/eslint.config.js|quality"
|
|
33
|
+
["prettier"]="stubs/prettier.config.js.stub|config/dev-tools/prettier.config.js|style"
|
|
34
|
+
["stylelint"]="stubs/stylelint.config.js.stub|config/dev-tools/stylelint.config.js|style"
|
|
35
|
+
["prettierignore"]="config/.prettierignore|config/dev-tools/.prettierignore|style"
|
|
36
|
+
["stylelintignore"]="config/.stylelintignore|config/dev-tools/.stylelintignore|style"
|
|
37
|
+
["markdownlint"]="config/.markdownlint.json|config/dev-tools/.markdownlint.json|style"
|
|
38
|
+
["markdownlintignore"]="config/.markdownlintignore|config/dev-tools/.markdownlintignore|style"
|
|
39
|
+
["vitest"]="stubs/vitest.config.js.stub|config/dev-tools/vitest.config.js|testing"
|
|
40
|
+
["tsconfig"]="stubs/tsconfig.json.stub|tsconfig.json|typescript"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
declare -A PUBLISH_GROUPS=(
|
|
44
|
+
["quality"]="eslint"
|
|
45
|
+
["style"]="prettier stylelint prettierignore stylelintignore markdownlint markdownlintignore"
|
|
46
|
+
["testing"]="vitest"
|
|
47
|
+
["typescript"]="tsconfig"
|
|
48
|
+
["all"]="eslint prettier stylelint prettierignore stylelintignore markdownlint markdownlintignore vitest tsconfig"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# ============================================================================
|
|
52
|
+
# Argument Parsing
|
|
53
|
+
# ============================================================================
|
|
54
|
+
|
|
55
|
+
FORCE_OVERWRITE=false
|
|
56
|
+
SILENT_MODE=false
|
|
57
|
+
PUBLISH_TARGET=""
|
|
58
|
+
WITH_MAKEFILE=false
|
|
59
|
+
|
|
60
|
+
for arg in "$@"; do
|
|
61
|
+
case "$arg" in
|
|
62
|
+
--force|-f) FORCE_OVERWRITE=true ;;
|
|
63
|
+
--silent|-s) SILENT_MODE=true ;;
|
|
64
|
+
--with-makefile) WITH_MAKEFILE=true ;;
|
|
65
|
+
--publish) PUBLISH_TARGET="all" ;;
|
|
66
|
+
--publish=*) PUBLISH_TARGET="${arg#--publish=}" ;;
|
|
67
|
+
--help|-h)
|
|
68
|
+
echo ""
|
|
69
|
+
echo "Usage: bash setup-project.sh [options]"
|
|
70
|
+
echo ""
|
|
71
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
72
|
+
echo " Options"
|
|
73
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
74
|
+
echo " (no options) Normal setup (Makefile + .editorconfig + eslint baseline)"
|
|
75
|
+
echo " --publish Publish ALL configs to config/dev-tools/"
|
|
76
|
+
echo " --publish=<group> Publish a config group"
|
|
77
|
+
echo " --publish=<key> Publish a specific config"
|
|
78
|
+
echo " --with-makefile Generate or inject Makefile"
|
|
79
|
+
echo " --force, -f Overwrite existing files"
|
|
80
|
+
echo " --silent, -s Suppress output (for postinstall)"
|
|
81
|
+
echo " --help, -h Show this help"
|
|
82
|
+
echo ""
|
|
83
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
84
|
+
echo " Groups (--publish=<group>)"
|
|
85
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
86
|
+
echo " quality eslint"
|
|
87
|
+
echo " style prettier, stylelint, markdownlint, .prettierignore, .stylelintignore, .markdownlintignore"
|
|
88
|
+
echo " testing vitest"
|
|
89
|
+
echo " typescript tsconfig"
|
|
90
|
+
echo " all all configs (except gitlab-ci)"
|
|
91
|
+
echo ""
|
|
92
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
93
|
+
echo " Specific configs (--publish=<key>)"
|
|
94
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
95
|
+
echo " eslint → config/dev-tools/eslint.config.js"
|
|
96
|
+
echo " prettier → config/dev-tools/prettier.config.js"
|
|
97
|
+
echo " stylelint → config/dev-tools/stylelint.config.js"
|
|
98
|
+
echo " prettierignore → config/dev-tools/.prettierignore"
|
|
99
|
+
echo " stylelintignore → config/dev-tools/.stylelintignore"
|
|
100
|
+
echo " markdownlint → config/dev-tools/.markdownlint.json"
|
|
101
|
+
echo " markdownlintignore → config/dev-tools/.markdownlintignore"
|
|
102
|
+
echo " vitest → config/dev-tools/vitest.config.js"
|
|
103
|
+
echo " tsconfig → tsconfig.json (extends bundled base)"
|
|
104
|
+
echo " gitlab-ci → auto-detect: .gitlab-ci.yml or .gitlab/pipeline-js.yml"
|
|
105
|
+
echo ""
|
|
106
|
+
exit 0
|
|
107
|
+
;;
|
|
108
|
+
*)
|
|
109
|
+
echo "ERROR: Unknown option: $arg" >&2
|
|
110
|
+
echo "Use --help for usage information" >&2
|
|
111
|
+
exit 1
|
|
112
|
+
;;
|
|
113
|
+
esac
|
|
114
|
+
done
|
|
115
|
+
|
|
116
|
+
# ============================================================================
|
|
117
|
+
# Silent Mode Override
|
|
118
|
+
# ============================================================================
|
|
119
|
+
|
|
120
|
+
if [[ "$SILENT_MODE" == "true" ]]; then
|
|
121
|
+
log_header() { :; }
|
|
122
|
+
log_step() { :; }
|
|
123
|
+
log_info() { :; }
|
|
124
|
+
log_success() { :; }
|
|
125
|
+
log_warning() { :; }
|
|
126
|
+
fi
|
|
127
|
+
|
|
128
|
+
# ============================================================================
|
|
129
|
+
# Optional Dependencies Check
|
|
130
|
+
# Runs after setup — shows informative messages even in silent mode (postinstall)
|
|
131
|
+
# ============================================================================
|
|
132
|
+
|
|
133
|
+
check_optional_deps() {
|
|
134
|
+
local -a missing=()
|
|
135
|
+
|
|
136
|
+
# zod — runtime type validation (validates API responses / form inputs at runtime)
|
|
137
|
+
[[ ! -d "${PROJECT_ROOT}/node_modules/zod" ]] \
|
|
138
|
+
&& missing+=("zod|Runtime type validation for JS/Vue (validates API responses, forms)|${PM} install zod")
|
|
139
|
+
|
|
140
|
+
# typescript — enables make typecheck and make build
|
|
141
|
+
[[ ! -d "${PROJECT_ROOT}/node_modules/typescript" ]] \
|
|
142
|
+
&& missing+=("typescript|TypeScript compiler — enables make typecheck + make build|${PM} install --save-dev typescript")
|
|
143
|
+
|
|
144
|
+
# tsup — fast TS bundler (recommended for npm packages to publish)
|
|
145
|
+
[[ ! -d "${PROJECT_ROOT}/node_modules/tsup" ]] \
|
|
146
|
+
&& missing+=("tsup|Fast TypeScript bundler for npm packages (esbuild-based)|${PM} install --save-dev tsup")
|
|
147
|
+
|
|
148
|
+
# knip — unused exports, files and dependencies detector
|
|
149
|
+
[[ ! -d "${PROJECT_ROOT}/node_modules/knip" ]] \
|
|
150
|
+
&& missing+=("knip|Unused exports and dependencies detector (make knip)|${PM} install --save-dev knip")
|
|
151
|
+
|
|
152
|
+
[[ ${#missing[@]} -eq 0 ]] && return 0
|
|
153
|
+
|
|
154
|
+
if [[ "$SILENT_MODE" == "true" ]]; then
|
|
155
|
+
echo ""
|
|
156
|
+
echo " ┌─ @zairakai/dev-tools — optional packages not installed ─┐"
|
|
157
|
+
for entry in "${missing[@]}"; do
|
|
158
|
+
local pkg="${entry%%|*}"
|
|
159
|
+
local rest="${entry#*|}"
|
|
160
|
+
local install_cmd="${rest#*|}"
|
|
161
|
+
printf " │ %-12s %s\n" "${pkg}" "${install_cmd}"
|
|
162
|
+
done
|
|
163
|
+
echo " └─ Run: bash setup-project.sh (without --silent) for details ┘"
|
|
164
|
+
echo ""
|
|
165
|
+
return 0
|
|
166
|
+
fi
|
|
167
|
+
|
|
168
|
+
echo ""
|
|
169
|
+
echo -e "${YELLOW}┌──────────────────────────────────────────────────────┐${NC}"
|
|
170
|
+
echo -e "${YELLOW}│${NC} ${YELLOW}Recommended Optional Packages${NC} ${YELLOW}│${NC}"
|
|
171
|
+
echo -e "${YELLOW}├──────────────────────────────────────────────────────┤${NC}"
|
|
172
|
+
for entry in "${missing[@]}"; do
|
|
173
|
+
local pkg="${entry%%|*}"
|
|
174
|
+
local rest="${entry#*|}"
|
|
175
|
+
local reason="${rest%%|*}"
|
|
176
|
+
local install_cmd="${rest#*|}"
|
|
177
|
+
echo -e "${YELLOW}│${NC} ${CYAN}${pkg}${NC}"
|
|
178
|
+
echo -e "${YELLOW}│${NC} ${reason}"
|
|
179
|
+
echo -e "${YELLOW}│${NC} ${GREEN}${install_cmd}${NC}"
|
|
180
|
+
echo -e "${YELLOW}│${NC}"
|
|
181
|
+
done
|
|
182
|
+
echo -e "${YELLOW}└──────────────────────────────────────────────────────┘${NC}"
|
|
183
|
+
echo ""
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
# ============================================================================
|
|
187
|
+
# Result Tracking
|
|
188
|
+
# ============================================================================
|
|
189
|
+
|
|
190
|
+
declare -a CREATED_FILES=()
|
|
191
|
+
declare -a SKIPPED_FILES=()
|
|
192
|
+
declare -a BACKED_UP_FILES=()
|
|
193
|
+
declare -a PUBLISHED_FILES=()
|
|
194
|
+
|
|
195
|
+
track_created() { CREATED_FILES+=("$1"); }
|
|
196
|
+
track_skipped() { SKIPPED_FILES+=("$1"); }
|
|
197
|
+
track_backed_up() { BACKED_UP_FILES+=("$1"); }
|
|
198
|
+
track_published() { PUBLISHED_FILES+=("$1"); }
|
|
199
|
+
|
|
200
|
+
# ============================================================================
|
|
201
|
+
# File Helpers
|
|
202
|
+
# ============================================================================
|
|
203
|
+
|
|
204
|
+
# Publish a config to config/dev-tools/ (user-facing, hash-protected)
|
|
205
|
+
publish_file() {
|
|
206
|
+
local source="$1"
|
|
207
|
+
local target="$2"
|
|
208
|
+
local name="$3"
|
|
209
|
+
|
|
210
|
+
if [[ ! -f "$source" ]]; then
|
|
211
|
+
log_warning "Source not found for ${name}: ${source#"$DEV_TOOLS_ROOT"/}"
|
|
212
|
+
return 0
|
|
213
|
+
fi
|
|
214
|
+
|
|
215
|
+
if [[ -f "$target" ]] && [[ "$FORCE_OVERWRITE" != "true" ]]; then
|
|
216
|
+
local src_hash tgt_hash
|
|
217
|
+
src_hash="$(file_hash "$source")"
|
|
218
|
+
tgt_hash="$(file_hash "$target")"
|
|
219
|
+
|
|
220
|
+
if [[ -n "$src_hash" ]] && [[ "$src_hash" == "$tgt_hash" ]]; then
|
|
221
|
+
cp "$source" "$target"
|
|
222
|
+
track_published "${name} → ${target#"$PROJECT_ROOT"/} (refreshed)"
|
|
223
|
+
else
|
|
224
|
+
track_skipped "$name"
|
|
225
|
+
log_info "Skipping modified: ${name} (use --force to overwrite)"
|
|
226
|
+
fi
|
|
227
|
+
return 0
|
|
228
|
+
fi
|
|
229
|
+
|
|
230
|
+
if [[ -f "$target" ]] && [[ "$FORCE_OVERWRITE" == "true" ]]; then
|
|
231
|
+
if backup_file "$target" 2>/dev/null; then
|
|
232
|
+
track_backed_up "$name"
|
|
233
|
+
fi
|
|
234
|
+
fi
|
|
235
|
+
|
|
236
|
+
mkdir -p "$(dirname "$target")"
|
|
237
|
+
cp "$source" "$target"
|
|
238
|
+
track_published "${name} → ${target#"$PROJECT_ROOT"/}"
|
|
239
|
+
log_success "Published: ${name} → ${target#"$PROJECT_ROOT"/}"
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
# Copy file for standard setup (skips if exists unless --force)
|
|
243
|
+
setup_file() {
|
|
244
|
+
local source="$1"
|
|
245
|
+
local target="$2"
|
|
246
|
+
local name="$3"
|
|
247
|
+
|
|
248
|
+
if [[ "$FORCE_OVERWRITE" == "true" ]]; then
|
|
249
|
+
if [[ -f "$target" ]] && [[ ! -L "$target" ]]; then
|
|
250
|
+
if backup_file "$target" 2>/dev/null; then
|
|
251
|
+
track_backed_up "$name"
|
|
252
|
+
fi
|
|
253
|
+
fi
|
|
254
|
+
rm -f "$target" 2>/dev/null || true
|
|
255
|
+
mkdir -p "$(dirname "$target")"
|
|
256
|
+
if cp "$source" "$target" 2>/dev/null; then
|
|
257
|
+
track_created "$name"
|
|
258
|
+
log_success "Created: $name"
|
|
259
|
+
fi
|
|
260
|
+
else
|
|
261
|
+
if [[ -f "$target" ]] || [[ -L "$target" ]]; then
|
|
262
|
+
track_skipped "$name"
|
|
263
|
+
return 0
|
|
264
|
+
fi
|
|
265
|
+
mkdir -p "$(dirname "$target")"
|
|
266
|
+
if cp "$source" "$target" 2>/dev/null; then
|
|
267
|
+
track_created "$name"
|
|
268
|
+
log_success "Created: $name"
|
|
269
|
+
fi
|
|
270
|
+
fi
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
# ============================================================================
|
|
274
|
+
# GitLab CI — Placeholder Replacement Helper
|
|
275
|
+
# ============================================================================
|
|
276
|
+
|
|
277
|
+
# Extract package name and derive cache key from package.json
|
|
278
|
+
get_package_info() {
|
|
279
|
+
local pkg_name pkg_cache_key
|
|
280
|
+
|
|
281
|
+
pkg_name="$(node -e "try{const p=require('${PROJECT_ROOT}/package.json');console.log(p.name||'')}catch(e){}" 2>/dev/null || echo "")"
|
|
282
|
+
pkg_cache_key="${pkg_name##*/}" # strip scope: @org/my-pkg → my-pkg
|
|
283
|
+
pkg_cache_key="${pkg_cache_key}-v1"
|
|
284
|
+
|
|
285
|
+
echo "${pkg_name}|${pkg_cache_key}"
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
# Replace placeholders in a published GitLab CI file
|
|
289
|
+
replace_gitlab_ci_placeholders() {
|
|
290
|
+
local target="$1"
|
|
291
|
+
local pkg_info
|
|
292
|
+
pkg_info="$(get_package_info)"
|
|
293
|
+
|
|
294
|
+
local pkg_name="${pkg_info%%|*}"
|
|
295
|
+
local pkg_cache_key="${pkg_info#*|}"
|
|
296
|
+
|
|
297
|
+
if [[ -n "$pkg_name" ]]; then
|
|
298
|
+
sed -i "s|PACKAGE_NPM_NAME|${pkg_name}|g" "$target"
|
|
299
|
+
sed -i "s|PACKAGE_CACHE_KEY|${pkg_cache_key}|g" "$target"
|
|
300
|
+
fi
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
# ============================================================================
|
|
304
|
+
# GitLab CI — NPM Package (.gitlab-ci.yml)
|
|
305
|
+
# ============================================================================
|
|
306
|
+
|
|
307
|
+
publish_gitlab_ci_npm() {
|
|
308
|
+
local source="${DEV_TOOLS_ROOT}/stubs/gitlab-ci.yml.stub"
|
|
309
|
+
local target="${PROJECT_ROOT}/.gitlab-ci.yml"
|
|
310
|
+
local name="gitlab-ci"
|
|
311
|
+
|
|
312
|
+
if [[ ! -f "$source" ]]; then
|
|
313
|
+
log_warning "Stub not found: stubs/gitlab-ci.yml.stub"
|
|
314
|
+
return 0
|
|
315
|
+
fi
|
|
316
|
+
|
|
317
|
+
if [[ -f "$target" ]] && [[ "$FORCE_OVERWRITE" != "true" ]]; then
|
|
318
|
+
track_skipped "$name"
|
|
319
|
+
log_info "Already exists: .gitlab-ci.yml (use --force to overwrite)"
|
|
320
|
+
return 0
|
|
321
|
+
fi
|
|
322
|
+
|
|
323
|
+
if [[ -f "$target" ]] && [[ "$FORCE_OVERWRITE" == "true" ]]; then
|
|
324
|
+
if backup_file "$target" 2>/dev/null; then
|
|
325
|
+
track_backed_up ".gitlab-ci.yml"
|
|
326
|
+
fi
|
|
327
|
+
fi
|
|
328
|
+
|
|
329
|
+
cp "$source" "$target"
|
|
330
|
+
replace_gitlab_ci_placeholders "$target"
|
|
331
|
+
|
|
332
|
+
track_published ".gitlab-ci.yml"
|
|
333
|
+
log_success "Published: .gitlab-ci.yml"
|
|
334
|
+
log_info "ref: v0.0.0 will be updated automatically on: ${PM} update @zairakai/dev-tools"
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
# ============================================================================
|
|
338
|
+
# GitLab CI — Laravel App (.gitlab/pipeline-js.yml + inject .gitlab-ci.yml)
|
|
339
|
+
# ============================================================================
|
|
340
|
+
|
|
341
|
+
# Publish .gitlab/pipeline-js.yml (the JS pipeline fragment)
|
|
342
|
+
publish_gitlab_pipeline_js() {
|
|
343
|
+
local source="${DEV_TOOLS_ROOT}/stubs/gitlab-pipeline-js.yml.stub"
|
|
344
|
+
local target="${PROJECT_ROOT}/.gitlab/pipeline-js.yml"
|
|
345
|
+
local name="gitlab/pipeline-js.yml"
|
|
346
|
+
|
|
347
|
+
if [[ ! -f "$source" ]]; then
|
|
348
|
+
log_warning "Stub not found: stubs/gitlab-pipeline-js.yml.stub"
|
|
349
|
+
return 0
|
|
350
|
+
fi
|
|
351
|
+
|
|
352
|
+
if [[ -f "$target" ]] && [[ "$FORCE_OVERWRITE" != "true" ]]; then
|
|
353
|
+
track_skipped "$name"
|
|
354
|
+
log_info "Already exists: .gitlab/pipeline-js.yml (use --force to overwrite)"
|
|
355
|
+
return 0
|
|
356
|
+
fi
|
|
357
|
+
|
|
358
|
+
if [[ -f "$target" ]] && [[ "$FORCE_OVERWRITE" == "true" ]]; then
|
|
359
|
+
if backup_file "$target" 2>/dev/null; then
|
|
360
|
+
track_backed_up ".gitlab/pipeline-js.yml"
|
|
361
|
+
fi
|
|
362
|
+
fi
|
|
363
|
+
|
|
364
|
+
mkdir -p "${PROJECT_ROOT}/.gitlab"
|
|
365
|
+
cp "$source" "$target"
|
|
366
|
+
replace_gitlab_ci_placeholders "$target"
|
|
367
|
+
|
|
368
|
+
track_published ".gitlab/pipeline-js.yml"
|
|
369
|
+
log_success "Published: .gitlab/pipeline-js.yml"
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
# Inject the local pipeline-js.yml include into .gitlab-ci.yml (or create it)
|
|
373
|
+
inject_or_create_gitlab_ci() {
|
|
374
|
+
local target="${PROJECT_ROOT}/.gitlab-ci.yml"
|
|
375
|
+
local marker="# @zairakai/dev-tools — JS"
|
|
376
|
+
|
|
377
|
+
if [[ ! -f "$target" ]]; then
|
|
378
|
+
# No .gitlab-ci.yml yet — create a minimal one
|
|
379
|
+
cat > "$target" << 'GITLAB_EOF'
|
|
380
|
+
# .gitlab-ci.yml
|
|
381
|
+
# Generated by @zairakai/dev-tools setup-project.sh
|
|
382
|
+
# To regenerate:
|
|
383
|
+
# bash node_modules/@zairakai/dev-tools/scripts/setup-project.sh --publish=gitlab-ci --force
|
|
384
|
+
|
|
385
|
+
include:
|
|
386
|
+
# JavaScript/frontend pipeline:
|
|
387
|
+
- local: '.gitlab/pipeline-js.yml'
|
|
388
|
+
|
|
389
|
+
# @zairakai/dev-tools — JS ────────────────────────────────────────────────────
|
|
390
|
+
GITLAB_EOF
|
|
391
|
+
track_created ".gitlab-ci.yml"
|
|
392
|
+
log_success "Created: .gitlab-ci.yml (includes .gitlab/pipeline-js.yml)"
|
|
393
|
+
return 0
|
|
394
|
+
fi
|
|
395
|
+
|
|
396
|
+
# .gitlab-ci.yml exists — check if already injected
|
|
397
|
+
if grep -qF "$marker" "$target" 2>/dev/null; then
|
|
398
|
+
log_info ".gitlab-ci.yml already includes pipeline-js.yml — skipping"
|
|
399
|
+
track_skipped ".gitlab-ci.yml (already injected)"
|
|
400
|
+
return 0
|
|
401
|
+
fi
|
|
402
|
+
|
|
403
|
+
log_info "Existing .gitlab-ci.yml detected — injecting pipeline-js.yml include"
|
|
404
|
+
|
|
405
|
+
if [[ "$FORCE_OVERWRITE" == "true" ]]; then
|
|
406
|
+
if backup_file "$target" 2>/dev/null; then
|
|
407
|
+
track_backed_up ".gitlab-ci.yml"
|
|
408
|
+
fi
|
|
409
|
+
fi
|
|
410
|
+
|
|
411
|
+
cat >> "$target" << 'INJECT_EOF'
|
|
412
|
+
|
|
413
|
+
# @zairakai/dev-tools — JS ────────────────────────────────────────────────────
|
|
414
|
+
# Injected by: bash node_modules/@zairakai/dev-tools/scripts/setup-project.sh --publish=gitlab-ci
|
|
415
|
+
# Adds JavaScript quality and test jobs.
|
|
416
|
+
include:
|
|
417
|
+
- local: '.gitlab/pipeline-js.yml'
|
|
418
|
+
INJECT_EOF
|
|
419
|
+
|
|
420
|
+
track_created ".gitlab-ci.yml (injected)"
|
|
421
|
+
log_success "Injected pipeline-js.yml include into .gitlab-ci.yml"
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
publish_gitlab_ci_laravel() {
|
|
425
|
+
publish_gitlab_pipeline_js
|
|
426
|
+
inject_or_create_gitlab_ci
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
# ============================================================================
|
|
430
|
+
# Publish Logic
|
|
431
|
+
# ============================================================================
|
|
432
|
+
|
|
433
|
+
resolve_publish_keys() {
|
|
434
|
+
local target="$1"
|
|
435
|
+
|
|
436
|
+
# Special handler — not in PUBLISHABLE
|
|
437
|
+
if [[ "$target" == "gitlab-ci" ]]; then
|
|
438
|
+
echo "$target"
|
|
439
|
+
return 0
|
|
440
|
+
fi
|
|
441
|
+
|
|
442
|
+
if [[ -n "${PUBLISH_GROUPS[$target]:-}" ]]; then
|
|
443
|
+
echo "${PUBLISH_GROUPS[$target]}"
|
|
444
|
+
return 0
|
|
445
|
+
fi
|
|
446
|
+
|
|
447
|
+
if [[ -n "${PUBLISHABLE[$target]:-}" ]]; then
|
|
448
|
+
echo "$target"
|
|
449
|
+
return 0
|
|
450
|
+
fi
|
|
451
|
+
|
|
452
|
+
log_error "Unknown publish target: '${target}'"
|
|
453
|
+
echo "" >&2
|
|
454
|
+
echo "Valid groups: ${!PUBLISH_GROUPS[*]}" >&2
|
|
455
|
+
echo "Valid configs: ${!PUBLISHABLE[*]} gitlab-ci" >&2
|
|
456
|
+
echo "Run --help for details" >&2
|
|
457
|
+
exit 1
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
# Dispatch --publish=gitlab-ci based on detected project type.
|
|
461
|
+
# When laravel-dev-tools is present, delegates to it so the fullstack stub
|
|
462
|
+
# (single source of truth in laravel-dev-tools) is used automatically.
|
|
463
|
+
publish_gitlab_ci() {
|
|
464
|
+
if [[ "$PROJECT_TYPE" == "laravel-app" ]]; then
|
|
465
|
+
local laravel_setup="${PROJECT_ROOT}/vendor/zairakai/laravel-dev-tools/scripts/setup-package.sh"
|
|
466
|
+
if [[ -f "$laravel_setup" ]]; then
|
|
467
|
+
log_info "laravel-dev-tools detected → delegating gitlab-ci publish (fullstack)"
|
|
468
|
+
local extra_args=()
|
|
469
|
+
[[ "$FORCE_OVERWRITE" == "true" ]] && extra_args+=("--force")
|
|
470
|
+
[[ "$SILENT_MODE" == "true" ]] && extra_args+=("--silent")
|
|
471
|
+
bash "$laravel_setup" --publish=gitlab-ci "${extra_args[@]}"
|
|
472
|
+
return 0
|
|
473
|
+
fi
|
|
474
|
+
log_info "Project type: laravel-app → publishing .gitlab/pipeline-js.yml"
|
|
475
|
+
publish_gitlab_ci_laravel
|
|
476
|
+
else
|
|
477
|
+
log_info "Project type: npm-package → publishing .gitlab-ci.yml"
|
|
478
|
+
publish_gitlab_ci_npm
|
|
479
|
+
fi
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
do_publish() {
|
|
483
|
+
local -a keys
|
|
484
|
+
read -ra keys <<< "$(resolve_publish_keys "$PUBLISH_TARGET")"
|
|
485
|
+
|
|
486
|
+
log_header "Publishing Dev Tools Configs"
|
|
487
|
+
|
|
488
|
+
for key in "${keys[@]}"; do
|
|
489
|
+
# Dispatch special handler — project-type aware
|
|
490
|
+
if [[ "$key" == "gitlab-ci" ]]; then
|
|
491
|
+
publish_gitlab_ci
|
|
492
|
+
continue
|
|
493
|
+
fi
|
|
494
|
+
|
|
495
|
+
local entry="${PUBLISHABLE[$key]:-}"
|
|
496
|
+
[[ -z "$entry" ]] && continue
|
|
497
|
+
|
|
498
|
+
local source_rel="${entry%%|*}"
|
|
499
|
+
local rest="${entry#*|}"
|
|
500
|
+
local target_rel="${rest%%|*}"
|
|
501
|
+
|
|
502
|
+
publish_file \
|
|
503
|
+
"${DEV_TOOLS_ROOT}/${source_rel}" \
|
|
504
|
+
"${PROJECT_ROOT}/${target_rel}" \
|
|
505
|
+
"$key"
|
|
506
|
+
done
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
# ============================================================================
|
|
510
|
+
# Makefile Setup
|
|
511
|
+
# ============================================================================
|
|
512
|
+
|
|
513
|
+
generate_makefile() {
|
|
514
|
+
local target="${PROJECT_ROOT}/Makefile"
|
|
515
|
+
local package_name
|
|
516
|
+
|
|
517
|
+
package_name="$(node -e "try{const p=require('${PROJECT_ROOT}/package.json');console.log(p.name||'')}catch(e){}" 2>/dev/null || echo "")"
|
|
518
|
+
|
|
519
|
+
cat > "$target" << 'MAKEFILE_EOF'
|
|
520
|
+
# Makefile
|
|
521
|
+
# Generated by @zairakai/dev-tools setup-project.sh
|
|
522
|
+
# Run `make help` to see available commands.
|
|
523
|
+
#
|
|
524
|
+
# To regenerate:
|
|
525
|
+
# bash node_modules/@zairakai/dev-tools/scripts/setup-project.sh --with-makefile --force
|
|
526
|
+
|
|
527
|
+
MAKEFILE_EOF
|
|
528
|
+
|
|
529
|
+
if [[ -n "$package_name" ]]; then
|
|
530
|
+
echo "NPM_DIRECTORY_TOOLS_PROJECT_NAME := \"${package_name}\"" >> "$target"
|
|
531
|
+
echo "" >> "$target"
|
|
532
|
+
fi
|
|
533
|
+
|
|
534
|
+
cat >> "$target" << 'MAKEFILE_EOF'
|
|
535
|
+
DEV_TOOLS_NPM := node_modules/@zairakai/dev-tools
|
|
536
|
+
|
|
537
|
+
include $(DEV_TOOLS_NPM)/tools/make/core.mk
|
|
538
|
+
MAKEFILE_EOF
|
|
539
|
+
|
|
540
|
+
track_created "Makefile"
|
|
541
|
+
log_success "Created: Makefile"
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
inject_makefile() {
|
|
545
|
+
local target="${PROJECT_ROOT}/Makefile"
|
|
546
|
+
local marker="# @zairakai/dev-tools"
|
|
547
|
+
|
|
548
|
+
if grep -qF "$marker" "$target" 2>/dev/null; then
|
|
549
|
+
log_info "Makefile already includes @zairakai/dev-tools — skipping"
|
|
550
|
+
track_skipped "Makefile (already injected)"
|
|
551
|
+
return 0
|
|
552
|
+
fi
|
|
553
|
+
|
|
554
|
+
log_info "Existing Makefile detected — injecting @zairakai/dev-tools includes"
|
|
555
|
+
|
|
556
|
+
cat >> "$target" << 'INJECT_EOF'
|
|
557
|
+
|
|
558
|
+
# ─── @zairakai/dev-tools ─────────────────────────────────────────────────────
|
|
559
|
+
# Injected by: bash node_modules/@zairakai/dev-tools/scripts/setup-project.sh --with-makefile
|
|
560
|
+
# Provides: eslint, prettier, stylelint, markdownlint, shellcheck, typecheck, build, knip, test, quality, bats targets
|
|
561
|
+
DEV_TOOLS_NPM := node_modules/@zairakai/dev-tools
|
|
562
|
+
-include $(DEV_TOOLS_NPM)/tools/make/variables.mk
|
|
563
|
+
-include $(DEV_TOOLS_NPM)/tools/make/help.mk
|
|
564
|
+
-include $(DEV_TOOLS_NPM)/tools/make/code-style.mk
|
|
565
|
+
-include $(DEV_TOOLS_NPM)/tools/make/stylelint.mk
|
|
566
|
+
-include $(DEV_TOOLS_NPM)/tools/make/markdownlint.mk
|
|
567
|
+
-include $(DEV_TOOLS_NPM)/tools/make/shellcheck.mk
|
|
568
|
+
-include $(DEV_TOOLS_NPM)/tools/make/typescript.mk
|
|
569
|
+
-include $(DEV_TOOLS_NPM)/tools/make/quality.mk
|
|
570
|
+
-include $(DEV_TOOLS_NPM)/tools/make/test.mk
|
|
571
|
+
-include $(DEV_TOOLS_NPM)/tools/make/bats.mk
|
|
572
|
+
INJECT_EOF
|
|
573
|
+
|
|
574
|
+
track_created "Makefile (injected)"
|
|
575
|
+
log_success "Injected @zairakai/dev-tools targets into existing Makefile"
|
|
576
|
+
log_info "Note: 'make help' will show JS targets alongside your existing targets"
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
setup_makefile() {
|
|
580
|
+
local target="${PROJECT_ROOT}/Makefile"
|
|
581
|
+
|
|
582
|
+
if [[ -f "$target" ]]; then
|
|
583
|
+
inject_makefile
|
|
584
|
+
else
|
|
585
|
+
generate_makefile
|
|
586
|
+
fi
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
# ============================================================================
|
|
590
|
+
# Main Setup
|
|
591
|
+
# ============================================================================
|
|
592
|
+
|
|
593
|
+
setup_project() {
|
|
594
|
+
[[ "$SILENT_MODE" != "true" ]] && {
|
|
595
|
+
echo ""
|
|
596
|
+
echo -e "${MAGENTA}📦 NPM Dev Tools Setup${NC}"
|
|
597
|
+
echo -e "${CYAN}Type:${NC} ${PROJECT_TYPE} | ${CYAN}Package manager:${NC} ${PM}"
|
|
598
|
+
echo ""
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
# ─── Publish mode ────────────────────────────────────────────────────────
|
|
602
|
+
if [[ -n "$PUBLISH_TARGET" ]]; then
|
|
603
|
+
do_publish
|
|
604
|
+
|
|
605
|
+
[[ "$WITH_MAKEFILE" == "true" ]] && setup_makefile
|
|
606
|
+
|
|
607
|
+
echo ""
|
|
608
|
+
echo -e "${MAGENTA}┌────────────────────────────────────────┐${NC}"
|
|
609
|
+
echo -e "${MAGENTA}│${NC} ${GREEN}Publish Complete${NC} ${MAGENTA}│${NC}"
|
|
610
|
+
echo -e "${MAGENTA}├────────────────────────────────────────┤${NC}"
|
|
611
|
+
|
|
612
|
+
for f in "${PUBLISHED_FILES[@]}"; do
|
|
613
|
+
echo -e "${MAGENTA}│${NC} ${GREEN}✓${NC} ${f}"
|
|
614
|
+
done
|
|
615
|
+
|
|
616
|
+
if [[ ${#CREATED_FILES[@]} -gt 0 ]]; then
|
|
617
|
+
for f in "${CREATED_FILES[@]}"; do
|
|
618
|
+
echo -e "${MAGENTA}│${NC} ${GREEN}✓${NC} ${f}"
|
|
619
|
+
done
|
|
620
|
+
fi
|
|
621
|
+
|
|
622
|
+
if [[ ${#SKIPPED_FILES[@]} -gt 0 ]]; then
|
|
623
|
+
echo -e "${MAGENTA}│${NC} ${YELLOW}○ Skipped (modified):${NC} ${SKIPPED_FILES[*]}"
|
|
624
|
+
echo -e "${MAGENTA}│${NC} ${YELLOW}→ Use --force to overwrite${NC}"
|
|
625
|
+
fi
|
|
626
|
+
|
|
627
|
+
if [[ ${#BACKED_UP_FILES[@]} -gt 0 ]]; then
|
|
628
|
+
echo -e "${MAGENTA}│${NC} ${CYAN}↩ Backed up:${NC} ${BACKED_UP_FILES[*]}"
|
|
629
|
+
echo -e "${MAGENTA}│${NC} ${CYAN}→ ${BACKUP_DIR}${NC}"
|
|
630
|
+
fi
|
|
631
|
+
|
|
632
|
+
echo -e "${MAGENTA}├────────────────────────────────────────┤${NC}"
|
|
633
|
+
echo -e "${MAGENTA}│${NC} ${CYAN}Edit configs in:${NC} config/dev-tools/"
|
|
634
|
+
echo -e "${MAGENTA}│${NC} ${CYAN}Help:${NC} bash setup-project.sh --help"
|
|
635
|
+
echo -e "${MAGENTA}└────────────────────────────────────────┘${NC}"
|
|
636
|
+
echo ""
|
|
637
|
+
exit 0
|
|
638
|
+
fi
|
|
639
|
+
|
|
640
|
+
# ─── Normal setup ────────────────────────────────────────────────────────
|
|
641
|
+
|
|
642
|
+
ensure_dir "${PROJECT_ROOT}/config/dev-tools"
|
|
643
|
+
|
|
644
|
+
if [[ "$PROJECT_TYPE" == "laravel-app" ]] \
|
|
645
|
+
&& [[ -f "${PROJECT_ROOT}/vendor/zairakai/laravel-dev-tools/scripts/setup-package.sh" ]]; then
|
|
646
|
+
log_info "Laravel app detected — delegating setup to laravel-dev-tools (full-stack)"
|
|
647
|
+
extra_args=()
|
|
648
|
+
[[ "$FORCE_OVERWRITE" == "true" ]] && extra_args+=("--force")
|
|
649
|
+
[[ "$SILENT_MODE" == "true" ]] && extra_args+=("--silent")
|
|
650
|
+
bash "${PROJECT_ROOT}/vendor/zairakai/laravel-dev-tools/scripts/setup-package.sh" --fullstack "${extra_args[@]}"
|
|
651
|
+
else
|
|
652
|
+
if [[ "$WITH_MAKEFILE" == "true" ]] || [[ ! -f "${PROJECT_ROOT}/Makefile" ]]; then
|
|
653
|
+
setup_makefile
|
|
654
|
+
fi
|
|
655
|
+
|
|
656
|
+
# .editorconfig (always copied - needed by IDEs)
|
|
657
|
+
setup_file "${DEV_TOOLS_ROOT}/.editorconfig" "${PROJECT_ROOT}/.editorconfig" ".editorconfig"
|
|
658
|
+
|
|
659
|
+
# ESLint baseline (published config only)
|
|
660
|
+
setup_file "${DEV_TOOLS_ROOT}/stubs/eslint.config.js.stub" \
|
|
661
|
+
"${PROJECT_ROOT}/config/dev-tools/eslint.config.js" \
|
|
662
|
+
"config/dev-tools/eslint.config.js"
|
|
663
|
+
fi
|
|
664
|
+
|
|
665
|
+
# ─── Summary ─────────────────────────────────────────────────────────────
|
|
666
|
+
if [[ "$SILENT_MODE" == "true" ]]; then
|
|
667
|
+
check_optional_deps
|
|
668
|
+
[[ ${#CREATED_FILES[@]} -eq 0 ]] && exit 0
|
|
669
|
+
fi
|
|
670
|
+
|
|
671
|
+
echo ""
|
|
672
|
+
echo -e "${MAGENTA}┌────────────────────────────────────────┐${NC}"
|
|
673
|
+
echo -e "${MAGENTA}│${NC} ${GREEN}Setup Complete${NC} ${MAGENTA}│${NC}"
|
|
674
|
+
echo -e "${MAGENTA}├────────────────────────────────────────┤${NC}"
|
|
675
|
+
|
|
676
|
+
if [[ ${#CREATED_FILES[@]} -gt 0 ]]; then
|
|
677
|
+
echo -e "${MAGENTA}│${NC} ${GREEN}✓ Created:${NC} ${CREATED_FILES[*]}"
|
|
678
|
+
fi
|
|
679
|
+
|
|
680
|
+
if [[ ${#SKIPPED_FILES[@]} -gt 0 ]]; then
|
|
681
|
+
echo -e "${MAGENTA}│${NC} ${YELLOW}○ Skipped:${NC} ${SKIPPED_FILES[*]}"
|
|
682
|
+
fi
|
|
683
|
+
|
|
684
|
+
if [[ ${#BACKED_UP_FILES[@]} -gt 0 ]]; then
|
|
685
|
+
echo -e "${MAGENTA}│${NC} ${CYAN}↩ Backed up:${NC} ${BACKED_UP_FILES[*]}"
|
|
686
|
+
echo -e "${MAGENTA}│${NC} ${CYAN}→ ${BACKUP_DIR}${NC}"
|
|
687
|
+
fi
|
|
688
|
+
|
|
689
|
+
echo -e "${MAGENTA}├────────────────────────────────────────┤${NC}"
|
|
690
|
+
echo -e "${MAGENTA}│${NC} ${CYAN}Type:${NC} ${PROJECT_TYPE} | ${CYAN}PM:${NC} ${PM}"
|
|
691
|
+
echo -e "${MAGENTA}│${NC} ${CYAN}Publish configs:${NC} bash setup-project.sh --publish"
|
|
692
|
+
echo -e "${MAGENTA}│${NC} ${CYAN}Run:${NC} make help"
|
|
693
|
+
echo -e "${MAGENTA}└────────────────────────────────────────┘${NC}"
|
|
694
|
+
|
|
695
|
+
check_optional_deps
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
# ============================================================================
|
|
699
|
+
# Execute
|
|
700
|
+
# ============================================================================
|
|
701
|
+
|
|
702
|
+
setup_project
|