@fredlackey/devutils 0.0.18 → 0.1.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/README.md +214 -141
- package/package.json +8 -83
- package/src/api/loader.js +229 -0
- package/src/api/registry.json +62 -0
- package/src/cli.js +293 -60
- package/src/commands/ai/index.js +16 -0
- package/src/commands/ai/launch.js +112 -0
- package/src/commands/ai/list.js +54 -0
- package/src/commands/ai/resume.js +70 -0
- package/src/commands/ai/sessions.js +121 -0
- package/src/commands/ai/set.js +131 -0
- package/src/commands/ai/show.js +74 -0
- package/src/commands/ai/tools.js +46 -0
- package/src/commands/alias/add.js +93 -0
- package/src/commands/alias/helpers.js +107 -0
- package/src/commands/alias/index.js +14 -0
- package/src/commands/alias/list.js +55 -0
- package/src/commands/alias/remove.js +62 -0
- package/src/commands/alias/sync.js +109 -0
- package/src/commands/api/disable.js +73 -0
- package/src/commands/api/enable.js +148 -0
- package/src/commands/api/index.js +15 -0
- package/src/commands/api/list.js +66 -0
- package/src/commands/api/update.js +87 -0
- package/src/commands/auth/index.js +15 -0
- package/src/commands/auth/list.js +49 -0
- package/src/commands/auth/login.js +384 -0
- package/src/commands/auth/logout.js +111 -0
- package/src/commands/auth/refresh.js +184 -0
- package/src/commands/auth/services.js +169 -0
- package/src/commands/auth/status.js +104 -0
- package/src/commands/config/export.js +224 -0
- package/src/commands/config/get.js +52 -0
- package/src/commands/config/import.js +308 -0
- package/src/commands/config/index.js +17 -0
- package/src/commands/config/init.js +143 -0
- package/src/commands/config/reset.js +57 -0
- package/src/commands/config/set.js +93 -0
- package/src/commands/config/show.js +35 -0
- package/src/commands/help.js +338 -0
- package/src/commands/identity/add.js +133 -0
- package/src/commands/identity/index.js +17 -0
- package/src/commands/identity/link.js +76 -0
- package/src/commands/identity/list.js +48 -0
- package/src/commands/identity/remove.js +72 -0
- package/src/commands/identity/show.js +65 -0
- package/src/commands/identity/sync.js +172 -0
- package/src/commands/identity/unlink.js +57 -0
- package/src/commands/ignore/add.js +165 -0
- package/src/commands/ignore/index.js +14 -0
- package/src/commands/ignore/list.js +89 -0
- package/src/commands/ignore/markers.js +43 -0
- package/src/commands/ignore/remove.js +164 -0
- package/src/commands/ignore/show.js +169 -0
- package/src/commands/machine/detect.js +122 -0
- package/src/commands/machine/index.js +14 -0
- package/src/commands/machine/list.js +74 -0
- package/src/commands/machine/set.js +106 -0
- package/src/commands/machine/show.js +35 -0
- package/src/commands/schema.js +152 -0
- package/src/commands/search/collections.js +134 -0
- package/src/commands/search/get.js +71 -0
- package/src/commands/search/index-cmd.js +54 -0
- package/src/commands/search/index.js +21 -0
- package/src/commands/search/keyword.js +60 -0
- package/src/commands/search/qmd.js +70 -0
- package/src/commands/search/query.js +64 -0
- package/src/commands/search/semantic.js +62 -0
- package/src/commands/search/status.js +46 -0
- package/src/commands/status.js +224 -171
- package/src/commands/tools/check.js +79 -0
- package/src/commands/tools/index.js +14 -0
- package/src/commands/tools/install.js +110 -0
- package/src/commands/tools/list.js +91 -0
- package/src/commands/tools/search.js +60 -0
- package/src/commands/update.js +83 -112
- package/src/commands/util/add.js +151 -0
- package/src/commands/util/index.js +15 -0
- package/src/commands/util/list.js +97 -0
- package/src/commands/util/remove.js +76 -0
- package/src/commands/util/run.js +79 -0
- package/src/commands/util/show.js +67 -0
- package/src/commands/version.js +21 -88
- package/src/installers/_template.js +104 -0
- package/src/installers/git.js +150 -0
- package/src/installers/homebrew.js +190 -0
- package/src/installers/node.js +223 -0
- package/src/installers/registry.json +29 -0
- package/src/lib/config.js +125 -0
- package/src/lib/detect.js +74 -0
- package/src/lib/errors.js +114 -0
- package/src/lib/github.js +315 -0
- package/src/lib/installer.js +225 -0
- package/src/lib/output.js +239 -0
- package/src/lib/platform.js +112 -0
- package/src/lib/platforms/amazon-linux.js +41 -0
- package/src/lib/platforms/gitbash.js +46 -0
- package/src/lib/platforms/macos.js +45 -0
- package/src/lib/platforms/raspbian.js +41 -0
- package/src/lib/platforms/ubuntu.js +39 -0
- package/src/lib/platforms/windows.js +45 -0
- package/src/lib/prompt.js +161 -0
- package/src/lib/schema.js +211 -0
- package/src/lib/shell.js +75 -0
- package/src/patterns/gitignore/claude-code.txt +25 -0
- package/src/patterns/gitignore/docker.txt +15 -0
- package/src/patterns/gitignore/go.txt +24 -0
- package/src/patterns/gitignore/java.txt +38 -0
- package/src/patterns/gitignore/jetbrains.txt +26 -0
- package/src/patterns/gitignore/linux.txt +18 -0
- package/src/patterns/gitignore/macos.txt +27 -0
- package/src/patterns/gitignore/node.txt +51 -0
- package/src/patterns/gitignore/python.txt +55 -0
- package/src/patterns/gitignore/rust.txt +14 -0
- package/src/patterns/gitignore/terraform.txt +30 -0
- package/src/patterns/gitignore/vscode.txt +15 -0
- package/src/patterns/gitignore/windows.txt +25 -0
- package/src/utils/clone/index.js +165 -0
- package/src/utils/git-push/index.js +230 -0
- package/src/utils/git-status/index.js +116 -0
- package/src/utils/git-status/unix.sh +75 -0
- package/src/utils/registry.json +41 -0
- package/bin/dev.js +0 -16
- package/files/README.md +0 -0
- package/files/claude/.claude/commands/setup-context.md +0 -3
- package/files/monorepos/_archive/README.md +0 -36
- package/files/monorepos/_legacy/README.md +0 -36
- package/files/monorepos/ai-docs/README.md +0 -33
- package/files/monorepos/apps/README.md +0 -24
- package/files/monorepos/docs/README.md +0 -40
- package/files/monorepos/packages/README.md +0 -25
- package/files/monorepos/research/README.md +0 -29
- package/files/monorepos/scripts/README.md +0 -24
- package/src/commands/README.md +0 -41
- package/src/commands/configure.js +0 -199
- package/src/commands/identity.js +0 -1630
- package/src/commands/ignore.js +0 -247
- package/src/commands/install.js +0 -526
- package/src/commands/setup.js +0 -246
- package/src/completion.js +0 -284
- package/src/constants.js +0 -45
- package/src/ignore/claude-code.txt +0 -10
- package/src/ignore/docker.txt +0 -18
- package/src/ignore/linux.txt +0 -23
- package/src/ignore/macos.txt +0 -36
- package/src/ignore/node.txt +0 -55
- package/src/ignore/terraform.txt +0 -37
- package/src/ignore/vscode.txt +0 -18
- package/src/ignore/windows.txt +0 -35
- package/src/index.js +0 -0
- package/src/installs/README.md +0 -399
- package/src/installs/adobe-creative-cloud.js +0 -546
- package/src/installs/adobe-creative-cloud.md +0 -605
- package/src/installs/appcleaner.js +0 -321
- package/src/installs/appcleaner.md +0 -699
- package/src/installs/apt-transport-https.js +0 -390
- package/src/installs/apt-transport-https.md +0 -678
- package/src/installs/atomicparsley.js +0 -642
- package/src/installs/atomicparsley.md +0 -795
- package/src/installs/aws-cli.js +0 -797
- package/src/installs/aws-cli.md +0 -727
- package/src/installs/balena-etcher.js +0 -710
- package/src/installs/balena-etcher.md +0 -761
- package/src/installs/bambu-studio.js +0 -1143
- package/src/installs/bambu-studio.md +0 -780
- package/src/installs/bash-completion.js +0 -575
- package/src/installs/bash-completion.md +0 -833
- package/src/installs/bash.js +0 -417
- package/src/installs/bash.md +0 -993
- package/src/installs/beyond-compare.js +0 -603
- package/src/installs/beyond-compare.md +0 -813
- package/src/installs/brave-browser.js +0 -968
- package/src/installs/brave-browser.md +0 -650
- package/src/installs/build-essential.js +0 -529
- package/src/installs/build-essential.md +0 -977
- package/src/installs/ca-certificates.js +0 -618
- package/src/installs/ca-certificates.md +0 -937
- package/src/installs/caffeine.js +0 -508
- package/src/installs/caffeine.md +0 -839
- package/src/installs/camtasia.js +0 -596
- package/src/installs/camtasia.md +0 -762
- package/src/installs/chatgpt.js +0 -476
- package/src/installs/chatgpt.md +0 -814
- package/src/installs/chocolatey.js +0 -456
- package/src/installs/chocolatey.md +0 -661
- package/src/installs/chrome-canary.js +0 -419
- package/src/installs/chrome-canary.md +0 -641
- package/src/installs/chromium.js +0 -667
- package/src/installs/chromium.md +0 -838
- package/src/installs/claude-code.js +0 -576
- package/src/installs/claude-code.md +0 -1173
- package/src/installs/cloudflare-warp.js +0 -900
- package/src/installs/cloudflare-warp.md +0 -1047
- package/src/installs/comet-browser.js +0 -588
- package/src/installs/comet-browser.md +0 -731
- package/src/installs/curl.js +0 -379
- package/src/installs/curl.md +0 -714
- package/src/installs/cursor.js +0 -579
- package/src/installs/cursor.md +0 -970
- package/src/installs/dbeaver.js +0 -924
- package/src/installs/dbeaver.md +0 -939
- package/src/installs/dbschema.js +0 -692
- package/src/installs/dbschema.md +0 -925
- package/src/installs/dependencies.md +0 -453
- package/src/installs/development-tools.js +0 -600
- package/src/installs/development-tools.md +0 -977
- package/src/installs/docker.js +0 -1029
- package/src/installs/docker.md +0 -1109
- package/src/installs/drawio.js +0 -1019
- package/src/installs/drawio.md +0 -795
- package/src/installs/elmedia-player.js +0 -347
- package/src/installs/elmedia-player.md +0 -556
- package/src/installs/ffmpeg.js +0 -889
- package/src/installs/ffmpeg.md +0 -852
- package/src/installs/file.js +0 -464
- package/src/installs/file.md +0 -987
- package/src/installs/gemini-cli.js +0 -811
- package/src/installs/gemini-cli.md +0 -1153
- package/src/installs/git.js +0 -400
- package/src/installs/git.md +0 -907
- package/src/installs/gitego.js +0 -949
- package/src/installs/gitego.md +0 -1172
- package/src/installs/go.js +0 -931
- package/src/installs/go.md +0 -958
- package/src/installs/google-antigravity.js +0 -913
- package/src/installs/google-antigravity.md +0 -1075
- package/src/installs/google-chrome.js +0 -833
- package/src/installs/google-chrome.md +0 -862
- package/src/installs/gpg.js +0 -480
- package/src/installs/gpg.md +0 -1056
- package/src/installs/homebrew.js +0 -1028
- package/src/installs/homebrew.md +0 -988
- package/src/installs/imageoptim.js +0 -968
- package/src/installs/imageoptim.md +0 -1119
- package/src/installs/installers.json +0 -4032
- package/src/installs/installers.json.tmp +0 -3953
- package/src/installs/jq.js +0 -400
- package/src/installs/jq.md +0 -809
- package/src/installs/keyboard-maestro.js +0 -719
- package/src/installs/keyboard-maestro.md +0 -825
- package/src/installs/kiro.js +0 -864
- package/src/installs/kiro.md +0 -1015
- package/src/installs/latex.js +0 -789
- package/src/installs/latex.md +0 -1095
- package/src/installs/lftp.js +0 -356
- package/src/installs/lftp.md +0 -907
- package/src/installs/lsb-release.js +0 -346
- package/src/installs/lsb-release.md +0 -814
- package/src/installs/messenger.js +0 -847
- package/src/installs/messenger.md +0 -900
- package/src/installs/microsoft-office.js +0 -568
- package/src/installs/microsoft-office.md +0 -760
- package/src/installs/microsoft-teams.js +0 -801
- package/src/installs/microsoft-teams.md +0 -886
- package/src/installs/moom.js +0 -326
- package/src/installs/moom.md +0 -570
- package/src/installs/node.js +0 -904
- package/src/installs/node.md +0 -1153
- package/src/installs/nordpass.js +0 -716
- package/src/installs/nordpass.md +0 -921
- package/src/installs/nordvpn.js +0 -892
- package/src/installs/nordvpn.md +0 -1052
- package/src/installs/nvm.js +0 -995
- package/src/installs/nvm.md +0 -1057
- package/src/installs/ohmyzsh.js +0 -529
- package/src/installs/ohmyzsh.md +0 -1094
- package/src/installs/openssh.js +0 -804
- package/src/installs/openssh.md +0 -1056
- package/src/installs/pandoc.js +0 -662
- package/src/installs/pandoc.md +0 -1036
- package/src/installs/parallels-desktop.js +0 -431
- package/src/installs/parallels-desktop.md +0 -446
- package/src/installs/pinentry.js +0 -510
- package/src/installs/pinentry.md +0 -1142
- package/src/installs/pngyu.js +0 -869
- package/src/installs/pngyu.md +0 -896
- package/src/installs/postman.js +0 -799
- package/src/installs/postman.md +0 -940
- package/src/installs/procps.js +0 -425
- package/src/installs/procps.md +0 -851
- package/src/installs/safari-tech-preview.js +0 -374
- package/src/installs/safari-tech-preview.md +0 -533
- package/src/installs/sfnt2woff.js +0 -658
- package/src/installs/sfnt2woff.md +0 -795
- package/src/installs/shellcheck.js +0 -481
- package/src/installs/shellcheck.md +0 -1005
- package/src/installs/slack.js +0 -741
- package/src/installs/slack.md +0 -865
- package/src/installs/snagit.js +0 -585
- package/src/installs/snagit.md +0 -844
- package/src/installs/software-properties-common.js +0 -372
- package/src/installs/software-properties-common.md +0 -805
- package/src/installs/spotify.js +0 -877
- package/src/installs/spotify.md +0 -901
- package/src/installs/studio-3t.js +0 -823
- package/src/installs/studio-3t.md +0 -918
- package/src/installs/sublime-text.js +0 -804
- package/src/installs/sublime-text.md +0 -914
- package/src/installs/superwhisper.js +0 -706
- package/src/installs/superwhisper.md +0 -630
- package/src/installs/tailscale.js +0 -745
- package/src/installs/tailscale.md +0 -1100
- package/src/installs/tar.js +0 -389
- package/src/installs/tar.md +0 -946
- package/src/installs/termius.js +0 -798
- package/src/installs/termius.md +0 -844
- package/src/installs/terraform.js +0 -779
- package/src/installs/terraform.md +0 -899
- package/src/installs/tfenv.js +0 -778
- package/src/installs/tfenv.md +0 -1091
- package/src/installs/tidal.js +0 -771
- package/src/installs/tidal.md +0 -864
- package/src/installs/tmux.js +0 -346
- package/src/installs/tmux.md +0 -1030
- package/src/installs/tree.js +0 -411
- package/src/installs/tree.md +0 -833
- package/src/installs/unzip.js +0 -460
- package/src/installs/unzip.md +0 -879
- package/src/installs/vim.js +0 -421
- package/src/installs/vim.md +0 -1040
- package/src/installs/vlc.js +0 -821
- package/src/installs/vlc.md +0 -927
- package/src/installs/vscode.js +0 -843
- package/src/installs/vscode.md +0 -1002
- package/src/installs/wget.js +0 -420
- package/src/installs/wget.md +0 -791
- package/src/installs/whatsapp.js +0 -729
- package/src/installs/whatsapp.md +0 -854
- package/src/installs/winpty.js +0 -352
- package/src/installs/winpty.md +0 -620
- package/src/installs/woff2.js +0 -553
- package/src/installs/woff2.md +0 -977
- package/src/installs/wsl.js +0 -572
- package/src/installs/wsl.md +0 -699
- package/src/installs/xcode-clt.js +0 -520
- package/src/installs/xcode-clt.md +0 -351
- package/src/installs/xcode.js +0 -560
- package/src/installs/xcode.md +0 -573
- package/src/installs/yarn.js +0 -824
- package/src/installs/yarn.md +0 -1074
- package/src/installs/yq.js +0 -654
- package/src/installs/yq.md +0 -944
- package/src/installs/yt-dlp.js +0 -701
- package/src/installs/yt-dlp.md +0 -946
- package/src/installs/yum-utils.js +0 -297
- package/src/installs/yum-utils.md +0 -648
- package/src/installs/zoom.js +0 -759
- package/src/installs/zoom.md +0 -884
- package/src/installs/zsh.js +0 -455
- package/src/installs/zsh.md +0 -1008
- package/src/scripts/README.md +0 -617
- package/src/scripts/STATUS.md +0 -208
- package/src/scripts/afk.js +0 -411
- package/src/scripts/backup-all.js +0 -746
- package/src/scripts/backup-source.js +0 -727
- package/src/scripts/brewd.js +0 -389
- package/src/scripts/brewi.js +0 -520
- package/src/scripts/brewr.js +0 -527
- package/src/scripts/brews.js +0 -477
- package/src/scripts/brewu.js +0 -504
- package/src/scripts/c.js +0 -201
- package/src/scripts/ccurl.js +0 -341
- package/src/scripts/certbot-crontab-init.js +0 -504
- package/src/scripts/certbot-init.js +0 -657
- package/src/scripts/ch.js +0 -355
- package/src/scripts/claude-danger.js +0 -268
- package/src/scripts/clean-dev.js +0 -435
- package/src/scripts/clear-dns-cache.js +0 -541
- package/src/scripts/clone.js +0 -435
- package/src/scripts/code-all.js +0 -437
- package/src/scripts/count-files.js +0 -211
- package/src/scripts/count-folders.js +0 -211
- package/src/scripts/count.js +0 -264
- package/src/scripts/d.js +0 -219
- package/src/scripts/datauri.js +0 -389
- package/src/scripts/delete-files.js +0 -380
- package/src/scripts/docker-clean.js +0 -426
- package/src/scripts/dp.js +0 -442
- package/src/scripts/e.js +0 -390
- package/src/scripts/empty-trash.js +0 -513
- package/src/scripts/evm.js +0 -444
- package/src/scripts/fetch-github-repos.js +0 -456
- package/src/scripts/get-channel.js +0 -345
- package/src/scripts/get-course.js +0 -399
- package/src/scripts/get-dependencies.js +0 -306
- package/src/scripts/get-folder.js +0 -799
- package/src/scripts/get-tunes.js +0 -426
- package/src/scripts/get-video.js +0 -367
- package/src/scripts/git-backup.js +0 -577
- package/src/scripts/git-clone.js +0 -493
- package/src/scripts/git-pup.js +0 -319
- package/src/scripts/git-push.js +0 -396
- package/src/scripts/h.js +0 -622
- package/src/scripts/hide-desktop-icons.js +0 -499
- package/src/scripts/hide-hidden-files.js +0 -538
- package/src/scripts/install-dependencies-from.js +0 -456
- package/src/scripts/ips.js +0 -663
- package/src/scripts/iso.js +0 -370
- package/src/scripts/killni.js +0 -577
- package/src/scripts/ll.js +0 -467
- package/src/scripts/local-ip.js +0 -325
- package/src/scripts/m.js +0 -524
- package/src/scripts/map.js +0 -309
- package/src/scripts/mkd.js +0 -351
- package/src/scripts/ncu-update-all.js +0 -457
- package/src/scripts/nginx-init.js +0 -718
- package/src/scripts/npmi.js +0 -382
- package/src/scripts/o.js +0 -511
- package/src/scripts/org-by-date.js +0 -338
- package/src/scripts/p.js +0 -224
- package/src/scripts/packages.js +0 -330
- package/src/scripts/path.js +0 -225
- package/src/scripts/ports.js +0 -597
- package/src/scripts/q.js +0 -305
- package/src/scripts/refresh-files.js +0 -394
- package/src/scripts/remove-smaller-files.js +0 -516
- package/src/scripts/rename-files-with-date.js +0 -533
- package/src/scripts/resize-image.js +0 -539
- package/src/scripts/rm-safe.js +0 -669
- package/src/scripts/s.js +0 -540
- package/src/scripts/set-git-public.js +0 -365
- package/src/scripts/show-desktop-icons.js +0 -475
- package/src/scripts/show-hidden-files.js +0 -472
- package/src/scripts/tpa.js +0 -280
- package/src/scripts/tpo.js +0 -280
- package/src/scripts/u.js +0 -505
- package/src/scripts/vpush.js +0 -437
- package/src/scripts/y.js +0 -283
- package/src/utils/README.md +0 -95
- package/src/utils/common/apps.js +0 -143
- package/src/utils/common/display.js +0 -157
- package/src/utils/common/network.js +0 -185
- package/src/utils/common/os.js +0 -294
- package/src/utils/common/package-manager.js +0 -301
- package/src/utils/common/privileges.js +0 -138
- package/src/utils/common/shell.js +0 -261
- package/src/utils/macos/apps.js +0 -228
- package/src/utils/macos/brew.js +0 -315
- package/src/utils/ubuntu/apt.js +0 -307
- package/src/utils/ubuntu/desktop.js +0 -292
- package/src/utils/ubuntu/snap.js +0 -344
- package/src/utils/ubuntu/systemd.js +0 -286
- package/src/utils/windows/choco.js +0 -465
- package/src/utils/windows/env.js +0 -246
- package/src/utils/windows/registry.js +0 -269
- package/src/utils/windows/shell.js +0 -240
- package/src/utils/windows/winget.js +0 -489
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const { MARKER_START, MARKER_END } = require('./markers');
|
|
6
|
+
|
|
7
|
+
const meta = {
|
|
8
|
+
description: 'Add gitignore patterns for a technology',
|
|
9
|
+
arguments: [
|
|
10
|
+
{ name: 'technology', description: 'Technology name (e.g., node, macos, docker)', required: true }
|
|
11
|
+
],
|
|
12
|
+
flags: [
|
|
13
|
+
{ name: 'path', description: 'Target directory (defaults to current directory)', type: 'string', default: '.' }
|
|
14
|
+
]
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Resolves the absolute path to a pattern file for a given technology.
|
|
19
|
+
* Uses __dirname so the path is relative to the installed package, not the
|
|
20
|
+
* user's working directory.
|
|
21
|
+
*
|
|
22
|
+
* @param {string} technology - Technology name (e.g., 'node').
|
|
23
|
+
* @returns {string} Absolute path to the pattern file.
|
|
24
|
+
*/
|
|
25
|
+
function getPatternFilePath(technology) {
|
|
26
|
+
return path.resolve(__dirname, '../../patterns/gitignore', `${technology}.txt`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Adds gitignore patterns for a technology to the .gitignore in the target
|
|
31
|
+
* directory. If the section already exists, it is replaced in place (idempotent).
|
|
32
|
+
* If the .gitignore does not exist, it is created.
|
|
33
|
+
*
|
|
34
|
+
* @param {object} args - Parsed command arguments ({ positional, flags }).
|
|
35
|
+
* @param {object} context - The DevUtils context object.
|
|
36
|
+
*/
|
|
37
|
+
async function run(args, context) {
|
|
38
|
+
const technology = args.positional[0];
|
|
39
|
+
|
|
40
|
+
// Validate: technology name is required
|
|
41
|
+
if (!technology) {
|
|
42
|
+
context.errors.throwError(400, 'Missing required argument: <technology>. Example: dev ignore add node', 'ignore');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Step A: Validate the technology name and read the pattern file
|
|
47
|
+
const patternFilePath = getPatternFilePath(technology);
|
|
48
|
+
if (!fs.existsSync(patternFilePath)) {
|
|
49
|
+
context.errors.throwError(404, `Unknown technology "${technology}". Run "dev ignore list" to see available options.`, 'ignore');
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const patternContent = fs.readFileSync(patternFilePath, 'utf8').trimEnd();
|
|
54
|
+
|
|
55
|
+
// Step B: Resolve the target .gitignore path
|
|
56
|
+
const flagPath = args.flags.path || '.';
|
|
57
|
+
const gitignorePath = path.resolve(flagPath, '.gitignore');
|
|
58
|
+
|
|
59
|
+
// Step C: Read existing .gitignore or start empty
|
|
60
|
+
let existingContent = '';
|
|
61
|
+
let fileExists = false;
|
|
62
|
+
if (fs.existsSync(gitignorePath)) {
|
|
63
|
+
existingContent = fs.readFileSync(gitignorePath, 'utf8');
|
|
64
|
+
fileExists = true;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Step D: Build the new section
|
|
68
|
+
const section = [
|
|
69
|
+
MARKER_START(technology),
|
|
70
|
+
patternContent,
|
|
71
|
+
MARKER_END(technology)
|
|
72
|
+
].join('\n');
|
|
73
|
+
|
|
74
|
+
// Step E: Check if the section already exists
|
|
75
|
+
const lines = existingContent.split(/\r?\n/);
|
|
76
|
+
const startMarker = MARKER_START(technology);
|
|
77
|
+
const endMarker = MARKER_END(technology);
|
|
78
|
+
const startIndex = lines.findIndex(line => line.trim() === startMarker);
|
|
79
|
+
const endIndex = lines.findIndex(line => line.trim() === endMarker);
|
|
80
|
+
|
|
81
|
+
let updatedContent;
|
|
82
|
+
let action;
|
|
83
|
+
|
|
84
|
+
if (startIndex !== -1 && endIndex !== -1 && endIndex > startIndex) {
|
|
85
|
+
// Both markers found: replace the existing section in place
|
|
86
|
+
const before = lines.slice(0, startIndex);
|
|
87
|
+
const after = lines.slice(endIndex + 1);
|
|
88
|
+
const sectionLines = section.split('\n');
|
|
89
|
+
const newLines = [...before, ...sectionLines, ...after];
|
|
90
|
+
updatedContent = newLines.join('\n');
|
|
91
|
+
action = 'updated';
|
|
92
|
+
} else if (startIndex !== -1 || endIndex !== -1) {
|
|
93
|
+
// Only one marker found: corrupted state. Warn and append.
|
|
94
|
+
if (!context.flags.quiet) {
|
|
95
|
+
context.output.info(`Warning: Found partial markers for "${technology}" in .gitignore. Appending new section at end.`);
|
|
96
|
+
}
|
|
97
|
+
updatedContent = existingContent;
|
|
98
|
+
// Ensure a blank line before the new section
|
|
99
|
+
if (updatedContent.length > 0 && !updatedContent.endsWith('\n\n') && !updatedContent.endsWith('\n')) {
|
|
100
|
+
updatedContent += '\n';
|
|
101
|
+
}
|
|
102
|
+
if (updatedContent.length > 0 && !updatedContent.endsWith('\n\n')) {
|
|
103
|
+
updatedContent += '\n';
|
|
104
|
+
}
|
|
105
|
+
updatedContent += section;
|
|
106
|
+
action = 'added';
|
|
107
|
+
} else {
|
|
108
|
+
// No markers found: fresh add, append to end
|
|
109
|
+
updatedContent = existingContent;
|
|
110
|
+
// Step F: Ensure a blank line before the new section
|
|
111
|
+
if (updatedContent.length > 0) {
|
|
112
|
+
if (!updatedContent.endsWith('\n')) {
|
|
113
|
+
updatedContent += '\n';
|
|
114
|
+
}
|
|
115
|
+
if (!updatedContent.endsWith('\n\n')) {
|
|
116
|
+
updatedContent += '\n';
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
updatedContent += section;
|
|
120
|
+
action = 'added';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Make sure the file ends with a trailing newline
|
|
124
|
+
if (!updatedContent.endsWith('\n')) {
|
|
125
|
+
updatedContent += '\n';
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Count pattern lines (lines between markers, not including markers)
|
|
129
|
+
const sectionLines = section.split('\n');
|
|
130
|
+
const patternLineCount = sectionLines.length - 2; // minus start and end markers
|
|
131
|
+
|
|
132
|
+
// Step G: Handle --dry-run
|
|
133
|
+
if (context.flags.dryRun) {
|
|
134
|
+
if (context.flags.format === 'json') {
|
|
135
|
+
context.output.out({
|
|
136
|
+
technology,
|
|
137
|
+
action,
|
|
138
|
+
path: gitignorePath,
|
|
139
|
+
lines: patternLineCount,
|
|
140
|
+
dryRun: true
|
|
141
|
+
});
|
|
142
|
+
} else {
|
|
143
|
+
context.output.info(`[dry-run] Would have ${action} ${technology} patterns in ${gitignorePath} (${patternLineCount} lines)`);
|
|
144
|
+
}
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Step G: Write the result
|
|
149
|
+
fs.writeFileSync(gitignorePath, updatedContent);
|
|
150
|
+
|
|
151
|
+
// Step H: Output the result
|
|
152
|
+
if (context.flags.format === 'json') {
|
|
153
|
+
context.output.out({
|
|
154
|
+
technology,
|
|
155
|
+
action,
|
|
156
|
+
path: gitignorePath,
|
|
157
|
+
lines: patternLineCount
|
|
158
|
+
});
|
|
159
|
+
} else {
|
|
160
|
+
const verb = action === 'updated' ? 'Updated' : 'Added';
|
|
161
|
+
context.output.info(`${verb} ${technology} patterns ${action === 'updated' ? 'in' : 'to'} .gitignore`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
module.exports = { meta, run };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ignore service registration.
|
|
3
|
+
* .gitignore pattern management.
|
|
4
|
+
*/
|
|
5
|
+
module.exports = {
|
|
6
|
+
name: 'ignore',
|
|
7
|
+
description: '.gitignore pattern management',
|
|
8
|
+
commands: {
|
|
9
|
+
add: () => require('./add'),
|
|
10
|
+
remove: () => require('./remove'),
|
|
11
|
+
list: () => require('./list'),
|
|
12
|
+
show: () => require('./show'),
|
|
13
|
+
}
|
|
14
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
|
|
6
|
+
const meta = {
|
|
7
|
+
description: 'List available gitignore pattern technologies',
|
|
8
|
+
arguments: [],
|
|
9
|
+
flags: []
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Returns the absolute path to the gitignore patterns directory.
|
|
14
|
+
* Uses __dirname so the path is relative to the installed package.
|
|
15
|
+
*
|
|
16
|
+
* @returns {string} Absolute path to the patterns directory.
|
|
17
|
+
*/
|
|
18
|
+
function getPatternsDir() {
|
|
19
|
+
return path.resolve(__dirname, '../../patterns/gitignore');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Lists all available gitignore pattern technologies by scanning the
|
|
24
|
+
* patterns directory. Each .txt file represents one technology. The
|
|
25
|
+
* technology name is the filename without the .txt extension.
|
|
26
|
+
*
|
|
27
|
+
* @param {object} args - Parsed command arguments ({ positional, flags }).
|
|
28
|
+
* @param {object} context - The DevUtils context object.
|
|
29
|
+
*/
|
|
30
|
+
async function run(args, context) {
|
|
31
|
+
const patternsDir = getPatternsDir();
|
|
32
|
+
|
|
33
|
+
// Step A: Read the patterns directory
|
|
34
|
+
if (!fs.existsSync(patternsDir)) {
|
|
35
|
+
context.errors.throwError(500, 'Patterns directory not found. The DevUtils installation may be corrupted.', 'ignore');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const files = fs.readdirSync(patternsDir)
|
|
40
|
+
.filter(f => f.endsWith('.txt'))
|
|
41
|
+
.sort();
|
|
42
|
+
|
|
43
|
+
if (files.length === 0) {
|
|
44
|
+
context.errors.throwError(500, 'No pattern files found. The DevUtils installation may be corrupted.', 'ignore');
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Step B: Read the first comment line from each file as a description
|
|
49
|
+
const technologies = files.map(file => {
|
|
50
|
+
const name = file.replace(/\.txt$/, '');
|
|
51
|
+
let description = name;
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
const content = fs.readFileSync(path.join(patternsDir, file), 'utf8');
|
|
55
|
+
const firstLine = content.split(/\r?\n/)[0];
|
|
56
|
+
if (firstLine && firstLine.startsWith('# ')) {
|
|
57
|
+
description = firstLine.slice(2).trim();
|
|
58
|
+
}
|
|
59
|
+
} catch {
|
|
60
|
+
// If we can't read the file, fall back to the name
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return { name, description };
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Step C: Build the result
|
|
67
|
+
const result = {
|
|
68
|
+
technologies,
|
|
69
|
+
count: technologies.length
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// Step D: Format the output
|
|
73
|
+
if (context.flags.format === 'json') {
|
|
74
|
+
context.output.out(result);
|
|
75
|
+
} else {
|
|
76
|
+
// Calculate padding for aligned columns
|
|
77
|
+
const maxNameLength = Math.max(...technologies.map(t => t.name.length));
|
|
78
|
+
|
|
79
|
+
context.output.info('Available technologies:');
|
|
80
|
+
for (const tech of technologies) {
|
|
81
|
+
const paddedName = tech.name.padEnd(maxNameLength + 2);
|
|
82
|
+
context.output.info(` ${paddedName}${tech.description}`);
|
|
83
|
+
}
|
|
84
|
+
context.output.info('');
|
|
85
|
+
context.output.info('Use "dev ignore add <technology>" to add patterns to .gitignore.');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = { meta, run };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shared marker constants for DevUtils-managed .gitignore sections.
|
|
5
|
+
*
|
|
6
|
+
* These markers wrap each technology's patterns so that the ignore commands
|
|
7
|
+
* can identify, replace, and remove sections without disturbing manually
|
|
8
|
+
* added patterns. The format is:
|
|
9
|
+
*
|
|
10
|
+
* # >>> devutils:<name>
|
|
11
|
+
* ... patterns ...
|
|
12
|
+
* # <<< devutils:<name>
|
|
13
|
+
*
|
|
14
|
+
* @module commands/ignore/markers
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Returns the start marker for a given technology name.
|
|
19
|
+
* @param {string} name - Technology name (e.g., 'node', 'macos').
|
|
20
|
+
* @returns {string} The start marker line.
|
|
21
|
+
*/
|
|
22
|
+
const MARKER_START = (name) => `# >>> devutils:${name}`;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Returns the end marker for a given technology name.
|
|
26
|
+
* @param {string} name - Technology name (e.g., 'node', 'macos').
|
|
27
|
+
* @returns {string} The end marker line.
|
|
28
|
+
*/
|
|
29
|
+
const MARKER_END = (name) => `# <<< devutils:${name}`;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The prefix used to identify start markers when parsing .gitignore files.
|
|
33
|
+
* @type {string}
|
|
34
|
+
*/
|
|
35
|
+
const MARKER_START_PREFIX = '# >>> devutils:';
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The prefix used to identify end markers when parsing .gitignore files.
|
|
39
|
+
* @type {string}
|
|
40
|
+
*/
|
|
41
|
+
const MARKER_END_PREFIX = '# <<< devutils:';
|
|
42
|
+
|
|
43
|
+
module.exports = { MARKER_START, MARKER_END, MARKER_START_PREFIX, MARKER_END_PREFIX };
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const { MARKER_START, MARKER_END } = require('./markers');
|
|
6
|
+
|
|
7
|
+
const meta = {
|
|
8
|
+
description: 'Remove managed gitignore patterns for a technology',
|
|
9
|
+
arguments: [
|
|
10
|
+
{ name: 'technology', description: 'Technology name to remove (e.g., node, macos)', required: true }
|
|
11
|
+
],
|
|
12
|
+
flags: [
|
|
13
|
+
{ name: 'path', description: 'Target directory (defaults to current directory)', type: 'string', default: '.' }
|
|
14
|
+
]
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Removes a DevUtils-managed section from the .gitignore in the target
|
|
19
|
+
* directory. If the section does not exist, this is a no-op (idempotent).
|
|
20
|
+
* If removing the section leaves the file empty, the file is deleted.
|
|
21
|
+
*
|
|
22
|
+
* @param {object} args - Parsed command arguments ({ positional, flags }).
|
|
23
|
+
* @param {object} context - The DevUtils context object.
|
|
24
|
+
*/
|
|
25
|
+
async function run(args, context) {
|
|
26
|
+
const technology = args.positional[0];
|
|
27
|
+
|
|
28
|
+
// Validate: technology name is required
|
|
29
|
+
if (!technology) {
|
|
30
|
+
context.errors.throwError(400, 'Missing required argument: <technology>. Example: dev ignore remove node', 'ignore');
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Step A: Resolve the .gitignore path
|
|
35
|
+
const flagPath = args.flags.path || '.';
|
|
36
|
+
const gitignorePath = path.resolve(flagPath, '.gitignore');
|
|
37
|
+
|
|
38
|
+
// Step B: Read existing .gitignore
|
|
39
|
+
if (!fs.existsSync(gitignorePath)) {
|
|
40
|
+
if (context.flags.format === 'json') {
|
|
41
|
+
context.output.out({
|
|
42
|
+
technology,
|
|
43
|
+
action: 'none',
|
|
44
|
+
message: `No .gitignore found at ${path.resolve(flagPath)}.`
|
|
45
|
+
});
|
|
46
|
+
} else {
|
|
47
|
+
context.output.info(`No .gitignore found at ${path.resolve(flagPath)}.`);
|
|
48
|
+
}
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const existingContent = fs.readFileSync(gitignorePath, 'utf8');
|
|
53
|
+
|
|
54
|
+
// Step C: Find the section markers
|
|
55
|
+
const lines = existingContent.split(/\r?\n/);
|
|
56
|
+
const startMarker = MARKER_START(technology);
|
|
57
|
+
const endMarker = MARKER_END(technology);
|
|
58
|
+
const startIndex = lines.findIndex(line => line.trim() === startMarker);
|
|
59
|
+
const endIndex = lines.findIndex(line => line.trim() === endMarker);
|
|
60
|
+
|
|
61
|
+
if (startIndex === -1 && endIndex === -1) {
|
|
62
|
+
// Section not present: no-op
|
|
63
|
+
if (context.flags.format === 'json') {
|
|
64
|
+
context.output.out({
|
|
65
|
+
technology,
|
|
66
|
+
action: 'none',
|
|
67
|
+
message: `No managed section for "${technology}" found in .gitignore.`
|
|
68
|
+
});
|
|
69
|
+
} else {
|
|
70
|
+
context.output.info(`No managed section for "${technology}" found in .gitignore.`);
|
|
71
|
+
}
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (startIndex === -1 || endIndex === -1 || endIndex <= startIndex) {
|
|
76
|
+
// Only one marker found or end before start: corrupted state
|
|
77
|
+
context.output.info(`Warning: Found partial or corrupted markers for "${technology}" in .gitignore. Please fix manually.`);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Step D: Remove the section (start through end marker, inclusive)
|
|
82
|
+
const before = lines.slice(0, startIndex);
|
|
83
|
+
let after = lines.slice(endIndex + 1);
|
|
84
|
+
|
|
85
|
+
// Clean up one trailing blank line after the end marker
|
|
86
|
+
if (after.length > 0 && after[0].trim() === '') {
|
|
87
|
+
after = after.slice(1);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
let newLines = [...before, ...after];
|
|
91
|
+
|
|
92
|
+
// Build the updated content
|
|
93
|
+
let updatedContent = newLines.join('\n');
|
|
94
|
+
|
|
95
|
+
// Step E: If the file is now empty (only whitespace), delete it
|
|
96
|
+
if (updatedContent.trim() === '') {
|
|
97
|
+
if (context.flags.dryRun) {
|
|
98
|
+
if (context.flags.format === 'json') {
|
|
99
|
+
context.output.out({
|
|
100
|
+
technology,
|
|
101
|
+
action: 'removed',
|
|
102
|
+
path: gitignorePath,
|
|
103
|
+
fileDeleted: true,
|
|
104
|
+
dryRun: true
|
|
105
|
+
});
|
|
106
|
+
} else {
|
|
107
|
+
context.output.info(`[dry-run] Would remove ${technology} patterns from .gitignore and delete the empty file`);
|
|
108
|
+
}
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
fs.unlinkSync(gitignorePath);
|
|
113
|
+
|
|
114
|
+
if (context.flags.format === 'json') {
|
|
115
|
+
context.output.out({
|
|
116
|
+
technology,
|
|
117
|
+
action: 'removed',
|
|
118
|
+
path: gitignorePath,
|
|
119
|
+
fileDeleted: true
|
|
120
|
+
});
|
|
121
|
+
} else {
|
|
122
|
+
context.output.info(`Removed ${technology} patterns from .gitignore (file deleted -- was empty)`);
|
|
123
|
+
}
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Make sure the file ends with a trailing newline
|
|
128
|
+
if (!updatedContent.endsWith('\n')) {
|
|
129
|
+
updatedContent += '\n';
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Handle --dry-run
|
|
133
|
+
if (context.flags.dryRun) {
|
|
134
|
+
if (context.flags.format === 'json') {
|
|
135
|
+
context.output.out({
|
|
136
|
+
technology,
|
|
137
|
+
action: 'removed',
|
|
138
|
+
path: gitignorePath,
|
|
139
|
+
fileDeleted: false,
|
|
140
|
+
dryRun: true
|
|
141
|
+
});
|
|
142
|
+
} else {
|
|
143
|
+
context.output.info(`[dry-run] Would remove ${technology} patterns from .gitignore`);
|
|
144
|
+
}
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Step E: Write the result
|
|
149
|
+
fs.writeFileSync(gitignorePath, updatedContent);
|
|
150
|
+
|
|
151
|
+
// Step F: Output the result
|
|
152
|
+
if (context.flags.format === 'json') {
|
|
153
|
+
context.output.out({
|
|
154
|
+
technology,
|
|
155
|
+
action: 'removed',
|
|
156
|
+
path: gitignorePath,
|
|
157
|
+
fileDeleted: false
|
|
158
|
+
});
|
|
159
|
+
} else {
|
|
160
|
+
context.output.info(`Removed ${technology} patterns from .gitignore`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
module.exports = { meta, run };
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const { MARKER_START_PREFIX, MARKER_END_PREFIX } = require('./markers');
|
|
6
|
+
|
|
7
|
+
const meta = {
|
|
8
|
+
description: 'Show managed gitignore sections in the current directory',
|
|
9
|
+
arguments: [],
|
|
10
|
+
flags: [
|
|
11
|
+
{ name: 'path', description: 'Target directory (defaults to current directory)', type: 'string', default: '.' }
|
|
12
|
+
]
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Scans the .gitignore in the target directory and reports which
|
|
17
|
+
* DevUtils-managed sections are present, including the technology name,
|
|
18
|
+
* pattern line count, and line range for each section. Also counts
|
|
19
|
+
* unmanaged lines (lines outside any DevUtils section that are not blank
|
|
20
|
+
* or comments).
|
|
21
|
+
*
|
|
22
|
+
* @param {object} args - Parsed command arguments ({ positional, flags }).
|
|
23
|
+
* @param {object} context - The DevUtils context object.
|
|
24
|
+
*/
|
|
25
|
+
async function run(args, context) {
|
|
26
|
+
// Step A: Resolve the .gitignore path
|
|
27
|
+
const flagPath = args.flags.path || '.';
|
|
28
|
+
const gitignorePath = path.resolve(flagPath, '.gitignore');
|
|
29
|
+
|
|
30
|
+
// Step B: Read the file
|
|
31
|
+
if (!fs.existsSync(gitignorePath)) {
|
|
32
|
+
if (context.flags.format === 'json') {
|
|
33
|
+
context.output.out({
|
|
34
|
+
path: gitignorePath,
|
|
35
|
+
sections: [],
|
|
36
|
+
count: 0,
|
|
37
|
+
unmanagedLines: 0,
|
|
38
|
+
message: `No .gitignore found at ${path.resolve(flagPath)}.`
|
|
39
|
+
});
|
|
40
|
+
} else {
|
|
41
|
+
context.output.info(`No .gitignore found at ${path.resolve(flagPath)}.`);
|
|
42
|
+
}
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const content = fs.readFileSync(gitignorePath, 'utf8');
|
|
47
|
+
const lines = content.split(/\r?\n/);
|
|
48
|
+
|
|
49
|
+
// Step C: Parse managed sections
|
|
50
|
+
const sections = [];
|
|
51
|
+
const managedLineIndices = new Set();
|
|
52
|
+
let i = 0;
|
|
53
|
+
|
|
54
|
+
while (i < lines.length) {
|
|
55
|
+
const trimmedLine = lines[i].trim();
|
|
56
|
+
|
|
57
|
+
if (trimmedLine.startsWith(MARKER_START_PREFIX)) {
|
|
58
|
+
// Found a start marker -- extract the technology name
|
|
59
|
+
const technology = trimmedLine.slice(MARKER_START_PREFIX.length);
|
|
60
|
+
const startLine = i + 1; // 1-indexed
|
|
61
|
+
managedLineIndices.add(i);
|
|
62
|
+
|
|
63
|
+
// Find the corresponding end marker
|
|
64
|
+
const expectedEnd = `# <<< devutils:${technology}`;
|
|
65
|
+
let endIdx = -1;
|
|
66
|
+
|
|
67
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
68
|
+
if (lines[j].trim() === expectedEnd) {
|
|
69
|
+
endIdx = j;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (endIdx !== -1) {
|
|
75
|
+
// Mark all lines in this section as managed
|
|
76
|
+
for (let k = i; k <= endIdx; k++) {
|
|
77
|
+
managedLineIndices.add(k);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const patternLineCount = endIdx - i - 1; // lines between markers
|
|
81
|
+
const endLine = endIdx + 1; // 1-indexed
|
|
82
|
+
|
|
83
|
+
sections.push({
|
|
84
|
+
technology,
|
|
85
|
+
lines: patternLineCount,
|
|
86
|
+
startLine,
|
|
87
|
+
endLine
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
i = endIdx + 1;
|
|
91
|
+
} else {
|
|
92
|
+
// Orphaned start marker -- no matching end
|
|
93
|
+
sections.push({
|
|
94
|
+
technology,
|
|
95
|
+
lines: null,
|
|
96
|
+
startLine,
|
|
97
|
+
endLine: null,
|
|
98
|
+
error: 'Missing end marker'
|
|
99
|
+
});
|
|
100
|
+
i++;
|
|
101
|
+
}
|
|
102
|
+
} else if (trimmedLine.startsWith(MARKER_END_PREFIX)) {
|
|
103
|
+
// Orphaned end marker -- no matching start
|
|
104
|
+
const technology = trimmedLine.slice(MARKER_END_PREFIX.length);
|
|
105
|
+
managedLineIndices.add(i);
|
|
106
|
+
sections.push({
|
|
107
|
+
technology,
|
|
108
|
+
lines: null,
|
|
109
|
+
startLine: null,
|
|
110
|
+
endLine: i + 1, // 1-indexed
|
|
111
|
+
error: 'Missing start marker'
|
|
112
|
+
});
|
|
113
|
+
i++;
|
|
114
|
+
} else {
|
|
115
|
+
i++;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Step D: Count unmanaged lines (not blank, not comments, not in a section)
|
|
120
|
+
let unmanagedLines = 0;
|
|
121
|
+
for (let idx = 0; idx < lines.length; idx++) {
|
|
122
|
+
if (managedLineIndices.has(idx)) continue;
|
|
123
|
+
const trimmed = lines[idx].trim();
|
|
124
|
+
if (trimmed === '') continue;
|
|
125
|
+
if (trimmed.startsWith('#')) continue;
|
|
126
|
+
unmanagedLines++;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Step E: Build the result
|
|
130
|
+
const result = {
|
|
131
|
+
path: gitignorePath,
|
|
132
|
+
sections,
|
|
133
|
+
count: sections.length,
|
|
134
|
+
unmanagedLines
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
// Step F: Format the output
|
|
138
|
+
if (context.flags.format === 'json') {
|
|
139
|
+
context.output.out(result);
|
|
140
|
+
} else {
|
|
141
|
+
if (sections.length === 0) {
|
|
142
|
+
context.output.info('No DevUtils-managed sections found in .gitignore.');
|
|
143
|
+
} else {
|
|
144
|
+
// Calculate padding for aligned columns
|
|
145
|
+
const maxNameLength = Math.max(...sections.map(s => s.technology.length));
|
|
146
|
+
const maxLinesLength = Math.max(...sections.map(s => s.lines !== null ? String(s.lines).length : 1));
|
|
147
|
+
|
|
148
|
+
context.output.info('Managed sections in .gitignore:');
|
|
149
|
+
for (const section of sections) {
|
|
150
|
+
if (section.error) {
|
|
151
|
+
const paddedName = section.technology.padEnd(maxNameLength + 2);
|
|
152
|
+
context.output.info(` ${paddedName}[${section.error}]`);
|
|
153
|
+
} else {
|
|
154
|
+
const paddedName = section.technology.padEnd(maxNameLength + 2);
|
|
155
|
+
const paddedLines = String(section.lines).padStart(maxLinesLength);
|
|
156
|
+
context.output.info(` ${paddedName}${paddedLines} patterns (lines ${section.startLine}-${section.endLine})`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
context.output.info('');
|
|
160
|
+
context.output.info(`${sections.length} managed section${sections.length === 1 ? '' : 's'}.`);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (unmanagedLines > 0) {
|
|
164
|
+
context.output.info(`Plus ${unmanagedLines} unmanaged line${unmanagedLines === 1 ? '' : 's'}.`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
module.exports = { meta, run };
|