@dimensional-innovations/tool-config 2.0.0 â 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -183
- package/bin/lib/formatting.js +103 -0
- package/bin/lib/handlers/stylelint.js +2 -2
- package/bin/lib/package-manager.js +87 -0
- package/bin/lib/ui.js +149 -21
- package/bin/lib/uninstall.js +199 -0
- package/bin/setup-tool-config.js +199 -21
- package/package.json +6 -4
- package/src/tools/stylelint/README.md +9 -9
package/bin/lib/ui.js
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* Handles help text, banners, and output formatting
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { createBox, createSeparator, SYMBOLS, colors } from './formatting.js'
|
|
7
|
+
|
|
6
8
|
const VERSION = '0.0.0-development'
|
|
7
9
|
|
|
8
10
|
/**
|
|
@@ -26,11 +28,12 @@ Options:
|
|
|
26
28
|
--all, -a Setup all tools (non-interactive)
|
|
27
29
|
--ci [provider] Setup CI/CD pipeline (gitlab, github, bitbucket)
|
|
28
30
|
--setup-ci Interactive CI/CD setup
|
|
31
|
+
--uninstall Remove tool configuration and scripts
|
|
29
32
|
--dry-run, -d Preview changes without writing files
|
|
30
33
|
--help, -h Show this help message
|
|
31
34
|
--version, -v Show version number
|
|
32
35
|
|
|
33
|
-
Examples:
|
|
36
|
+
Examples (Install):
|
|
34
37
|
setup-tool-config # Interactive mode
|
|
35
38
|
setup-tool-config eslint # Setup ESLint only
|
|
36
39
|
setup-tool-config --all # Setup all tools
|
|
@@ -40,6 +43,13 @@ Examples:
|
|
|
40
43
|
setup-tool-config --setup-ci # Interactive CI setup
|
|
41
44
|
setup-tool-config semantic-release --ci # Setup release + CI
|
|
42
45
|
|
|
46
|
+
Examples (Uninstall):
|
|
47
|
+
setup-tool-config --uninstall # Interactive uninstall
|
|
48
|
+
setup-tool-config --uninstall eslint # Remove ESLint only
|
|
49
|
+
setup-tool-config --uninstall --all # Remove all detected tools
|
|
50
|
+
setup-tool-config --uninstall --ci # Remove CI/CD configuration
|
|
51
|
+
setup-tool-config --uninstall --dry-run # Preview uninstall
|
|
52
|
+
|
|
43
53
|
For more information, visit:
|
|
44
54
|
https://gitlab.com/dimensional-innovations/tool-config
|
|
45
55
|
`)
|
|
@@ -53,19 +63,40 @@ export function showVersion() {
|
|
|
53
63
|
}
|
|
54
64
|
|
|
55
65
|
/**
|
|
56
|
-
* Show setup banner with detected configuration
|
|
66
|
+
* Show welcome and setup banner with detected configuration
|
|
57
67
|
*/
|
|
58
68
|
export function showBanner(detected) {
|
|
59
69
|
console.log('')
|
|
60
|
-
|
|
61
|
-
|
|
70
|
+
|
|
71
|
+
// Welcome box
|
|
72
|
+
const welcome = [
|
|
73
|
+
'đ Welcome to @dimensional-innovations/tool-config',
|
|
74
|
+
'',
|
|
75
|
+
'Zero-config setup for ESLint, Prettier, Stylelint,',
|
|
76
|
+
'TypeScript, and semantic-release.',
|
|
77
|
+
'',
|
|
78
|
+
'đĄ Navigation: ââ to move, Space to select, Enter to continue'
|
|
79
|
+
]
|
|
80
|
+
console.log(createBox(welcome))
|
|
81
|
+
|
|
82
|
+
console.log('')
|
|
83
|
+
|
|
84
|
+
// Condensed detection info
|
|
85
|
+
const detectedParts = []
|
|
86
|
+
if (detected.framework !== 'vanilla') {
|
|
87
|
+
detectedParts.push(detected.framework.charAt(0).toUpperCase() + detected.framework.slice(1))
|
|
88
|
+
}
|
|
89
|
+
if (detected.typescript) {
|
|
90
|
+
detectedParts.push('TypeScript')
|
|
91
|
+
}
|
|
92
|
+
if (detected.environment) {
|
|
93
|
+
detectedParts.push(detected.environment.charAt(0).toUpperCase() + detected.environment.slice(1))
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const detectedStr = detectedParts.length > 0 ? detectedParts.join(' âĸ ') : 'JavaScript project'
|
|
97
|
+
console.log(`đ Auto-detected: ${detectedStr}`)
|
|
62
98
|
console.log('')
|
|
63
|
-
console.log('
|
|
64
|
-
console.log(` Framework: ${detected.framework}`)
|
|
65
|
-
console.log(` Environment: ${detected.environment}`)
|
|
66
|
-
console.log(` TypeScript: ${detected.typescript ? 'Yes' : 'No'}`)
|
|
67
|
-
console.log(` Electron: ${detected.electron ? 'Yes' : 'No'}`)
|
|
68
|
-
console.log(` Git Provider: ${detected.gitProvider || 'Unknown'}`)
|
|
99
|
+
console.log('đĄ Recommended tools are pre-selected based on your project')
|
|
69
100
|
console.log('')
|
|
70
101
|
}
|
|
71
102
|
|
|
@@ -79,21 +110,70 @@ export function showSection(title) {
|
|
|
79
110
|
}
|
|
80
111
|
|
|
81
112
|
/**
|
|
82
|
-
* Show completion message
|
|
113
|
+
* Show completion message with detailed summary
|
|
114
|
+
* @param {boolean} dryRun - Whether this was a dry run
|
|
115
|
+
* @param {string[]} createdFiles - Files that were created
|
|
116
|
+
* @param {string[]} scripts - Scripts that were added
|
|
83
117
|
*/
|
|
84
|
-
export function showCompletion(dryRun) {
|
|
118
|
+
export function showCompletion(dryRun, createdFiles = [], scripts = []) {
|
|
85
119
|
console.log('')
|
|
120
|
+
|
|
86
121
|
if (dryRun) {
|
|
87
|
-
console.log(
|
|
88
|
-
console.log('
|
|
122
|
+
console.log(createSeparator())
|
|
123
|
+
console.log('')
|
|
124
|
+
const dryRunMsg = [
|
|
125
|
+
`${SYMBOLS.info} DRY RUN MODE - Preview only, no files created`,
|
|
126
|
+
'',
|
|
127
|
+
'Run without --dry-run to create these files'
|
|
128
|
+
]
|
|
129
|
+
console.log(createBox(dryRunMsg))
|
|
89
130
|
} else {
|
|
90
|
-
console.log(
|
|
131
|
+
console.log(createSeparator())
|
|
91
132
|
console.log('')
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
133
|
+
|
|
134
|
+
const completion = [colors.bold(colors.cyan('đ All done! Your project is ready.'))]
|
|
135
|
+
|
|
136
|
+
if (createdFiles.length > 0) {
|
|
137
|
+
completion.push('')
|
|
138
|
+
completion.push(
|
|
139
|
+
`đ Created ${createdFiles.length} config file${createdFiles.length > 1 ? 's' : ''}:`
|
|
140
|
+
)
|
|
141
|
+
createdFiles.forEach(file => {
|
|
142
|
+
completion.push(` âĸ ${file}`)
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (scripts.length > 0) {
|
|
147
|
+
completion.push('')
|
|
148
|
+
completion.push(`đĻ Added ${scripts.length} npm script${scripts.length > 1 ? 's' : ''}:`)
|
|
149
|
+
|
|
150
|
+
// Highlight check-all if present
|
|
151
|
+
const checkAllIndex = scripts.indexOf('check-all')
|
|
152
|
+
if (checkAllIndex !== -1) {
|
|
153
|
+
completion.push(` âĸ check-all â Run this to validate everything`)
|
|
154
|
+
scripts
|
|
155
|
+
.filter(s => s !== 'check-all')
|
|
156
|
+
.forEach(script => {
|
|
157
|
+
completion.push(` âĸ ${script}`)
|
|
158
|
+
})
|
|
159
|
+
} else {
|
|
160
|
+
scripts.forEach(script => {
|
|
161
|
+
completion.push(` âĸ ${script}`)
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
completion.push('')
|
|
167
|
+
completion.push('đ Quick start:')
|
|
168
|
+
if (scripts.includes('check-all')) {
|
|
169
|
+
completion.push(' npm run check-all')
|
|
170
|
+
} else if (scripts.length > 0) {
|
|
171
|
+
completion.push(` npm run ${scripts[0]}`)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
console.log(createBox(completion))
|
|
96
175
|
}
|
|
176
|
+
|
|
97
177
|
console.log('')
|
|
98
178
|
}
|
|
99
179
|
|
|
@@ -103,9 +183,57 @@ export function showCompletion(dryRun) {
|
|
|
103
183
|
export function showCICompletion(dryRun) {
|
|
104
184
|
console.log('')
|
|
105
185
|
if (dryRun) {
|
|
106
|
-
console.log(
|
|
186
|
+
console.log(`${SYMBOLS.info} Dry run mode - no files were modified`)
|
|
187
|
+
} else {
|
|
188
|
+
console.log(`${SYMBOLS.success} CI/CD setup complete!`)
|
|
189
|
+
}
|
|
190
|
+
console.log('')
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Show uninstall banner
|
|
195
|
+
*/
|
|
196
|
+
export function showUninstallBanner(installedTools, installedCI) {
|
|
197
|
+
console.log('')
|
|
198
|
+
console.log('đī¸ @dimensional-innovations/tool-config Uninstall')
|
|
199
|
+
console.log('â'.repeat(50))
|
|
200
|
+
console.log('')
|
|
201
|
+
console.log('â ī¸ WARNING: This will remove configuration files and scripts')
|
|
202
|
+
console.log(' Make sure you have committed or backed up your changes first!')
|
|
203
|
+
console.log('')
|
|
204
|
+
|
|
205
|
+
if (installedTools.length > 0) {
|
|
206
|
+
console.log('đĻ Detected tools:')
|
|
207
|
+
for (const tool of installedTools) {
|
|
208
|
+
console.log(` - ${tool}`)
|
|
209
|
+
}
|
|
210
|
+
console.log('')
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (installedCI) {
|
|
214
|
+
console.log(`đ Detected CI/CD: ${installedCI}`)
|
|
215
|
+
console.log('')
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (installedTools.length === 0 && !installedCI) {
|
|
219
|
+
console.log('âšī¸ No tools or CI configuration detected')
|
|
220
|
+
console.log('')
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Show uninstall completion message
|
|
226
|
+
*/
|
|
227
|
+
export function showUninstallCompletion(dryRun, removedCount) {
|
|
228
|
+
console.log('')
|
|
229
|
+
if (dryRun) {
|
|
230
|
+
console.log(`${SYMBOLS.info} Dry run mode - no files were modified`)
|
|
231
|
+
console.log(' Run without --dry-run to apply changes')
|
|
232
|
+
} else if (removedCount > 0) {
|
|
233
|
+
console.log(`${SYMBOLS.success} Uninstall complete!`)
|
|
234
|
+
console.log(` Removed ${removedCount} file(s) and their associated scripts`)
|
|
107
235
|
} else {
|
|
108
|
-
console.log(
|
|
236
|
+
console.log(`${SYMBOLS.info} Nothing was removed`)
|
|
109
237
|
}
|
|
110
238
|
console.log('')
|
|
111
239
|
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Uninstall utilities for setup-tool-config CLI
|
|
3
|
+
* Handles safe removal of config files, CI templates, and scripts
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { existsSync, readdirSync, readFileSync, rmSync } from 'fs'
|
|
7
|
+
import { join } from 'path'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Detect which tools are currently installed
|
|
11
|
+
* @param {string} cwd - Current working directory
|
|
12
|
+
* @returns {string[]} Array of installed tool names
|
|
13
|
+
*/
|
|
14
|
+
export function detectInstalledTools(cwd) {
|
|
15
|
+
const toolFiles = {
|
|
16
|
+
eslint: 'eslint.config.js',
|
|
17
|
+
prettier: 'prettier.config.js',
|
|
18
|
+
stylelint: 'stylelint.config.js',
|
|
19
|
+
typescript: 'tsconfig.json',
|
|
20
|
+
'semantic-release': 'release.config.js'
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const installed = []
|
|
24
|
+
for (const [tool, filename] of Object.entries(toolFiles)) {
|
|
25
|
+
if (existsSync(join(cwd, filename))) {
|
|
26
|
+
installed.push(tool)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return installed
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Detect which CI provider is installed
|
|
35
|
+
* @param {string} cwd - Current working directory
|
|
36
|
+
* @returns {string|null} Provider name or null
|
|
37
|
+
*/
|
|
38
|
+
export function detectInstalledCI(cwd) {
|
|
39
|
+
const ciFiles = {
|
|
40
|
+
gitlab: '.gitlab-ci.yml',
|
|
41
|
+
github: '.github/workflows/ci.yml',
|
|
42
|
+
bitbucket: 'bitbucket-pipelines.yml'
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
for (const [provider, filepath] of Object.entries(ciFiles)) {
|
|
46
|
+
if (existsSync(join(cwd, filepath))) {
|
|
47
|
+
return provider
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return null
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Check if a file's content matches the expected template
|
|
56
|
+
* @param {string} filepath - Path to file
|
|
57
|
+
* @param {string} expectedContent - Expected content
|
|
58
|
+
* @returns {boolean} True if content matches
|
|
59
|
+
*/
|
|
60
|
+
function contentMatches(filepath, expectedContent) {
|
|
61
|
+
if (!existsSync(filepath)) {
|
|
62
|
+
return false
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
const actualContent = readFileSync(filepath, 'utf8')
|
|
67
|
+
return actualContent.trim() === expectedContent.trim()
|
|
68
|
+
} catch {
|
|
69
|
+
return false
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Uninstall a tool by removing its config file
|
|
75
|
+
* @param {string} _tool - Tool name
|
|
76
|
+
* @param {Object} handler - Tool handler with getConfigFilename and generateConfigContent
|
|
77
|
+
* @param {string} cwd - Current working directory
|
|
78
|
+
* @param {boolean} dryRun - Preview mode
|
|
79
|
+
* @returns {boolean} True if uninstalled successfully
|
|
80
|
+
*/
|
|
81
|
+
export function uninstallTool(_tool, handler, cwd, dryRun = false) {
|
|
82
|
+
const filename = handler.getConfigFilename()
|
|
83
|
+
const filepath = join(cwd, filename)
|
|
84
|
+
|
|
85
|
+
if (!existsSync(filepath)) {
|
|
86
|
+
console.log(` âšī¸ ${filename} not found - already uninstalled`)
|
|
87
|
+
return false
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Check if file was modified by user
|
|
91
|
+
const expectedContent = handler.generateConfigContent()
|
|
92
|
+
const isUnmodified = contentMatches(filepath, expectedContent)
|
|
93
|
+
|
|
94
|
+
if (!isUnmodified) {
|
|
95
|
+
console.log(` â ī¸ ${filename} has been modified - skipping for safety`)
|
|
96
|
+
console.log(' Remove manually if you want to delete it')
|
|
97
|
+
return false
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (dryRun) {
|
|
101
|
+
console.log(` đī¸ Would remove: ${filename}`)
|
|
102
|
+
return true
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
rmSync(filepath)
|
|
107
|
+
console.log(` â
Removed: ${filename}`)
|
|
108
|
+
return true
|
|
109
|
+
} catch (error) {
|
|
110
|
+
console.error(` â Failed to remove ${filename}:`, error.message)
|
|
111
|
+
return false
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Uninstall CI/CD configuration
|
|
117
|
+
* @param {string} provider - CI provider (gitlab, github, bitbucket)
|
|
118
|
+
* @param {string} cwd - Current working directory
|
|
119
|
+
* @param {boolean} dryRun - Preview mode
|
|
120
|
+
* @returns {boolean} True if uninstalled successfully
|
|
121
|
+
*/
|
|
122
|
+
export function uninstallCIConfig(provider, cwd, dryRun = false) {
|
|
123
|
+
const ciPaths = {
|
|
124
|
+
gitlab: '.gitlab-ci.yml',
|
|
125
|
+
github: '.github/workflows/ci.yml',
|
|
126
|
+
bitbucket: 'bitbucket-pipelines.yml'
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const ciPath = ciPaths[provider]
|
|
130
|
+
if (!ciPath) {
|
|
131
|
+
console.log(` â ī¸ Unknown provider: ${provider}`)
|
|
132
|
+
return false
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const filepath = join(cwd, ciPath)
|
|
136
|
+
|
|
137
|
+
if (!existsSync(filepath)) {
|
|
138
|
+
console.log(` âšī¸ ${ciPath} not found - already uninstalled`)
|
|
139
|
+
return false
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (dryRun) {
|
|
143
|
+
console.log(` đī¸ Would remove: ${ciPath}`)
|
|
144
|
+
if (provider === 'github') {
|
|
145
|
+
console.log(` đī¸ Would clean up empty directories if needed`)
|
|
146
|
+
}
|
|
147
|
+
return true
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
rmSync(filepath)
|
|
152
|
+
console.log(` â
Removed: ${ciPath}`)
|
|
153
|
+
|
|
154
|
+
// Clean up empty directories for GitHub
|
|
155
|
+
if (provider === 'github') {
|
|
156
|
+
cleanupGitHubDirectories(cwd)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return true
|
|
160
|
+
} catch (error) {
|
|
161
|
+
console.error(` â Failed to remove ${ciPath}:`, error.message)
|
|
162
|
+
return false
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Clean up empty GitHub directories
|
|
168
|
+
* @param {string} cwd - Current working directory
|
|
169
|
+
*/
|
|
170
|
+
function cleanupGitHubDirectories(cwd) {
|
|
171
|
+
const workflowDir = join(cwd, '.github/workflows')
|
|
172
|
+
const githubDir = join(cwd, '.github')
|
|
173
|
+
|
|
174
|
+
// Remove .github/workflows if empty
|
|
175
|
+
if (existsSync(workflowDir)) {
|
|
176
|
+
try {
|
|
177
|
+
const files = readdirSync(workflowDir)
|
|
178
|
+
if (files.length === 0) {
|
|
179
|
+
rmSync(workflowDir, { recursive: true })
|
|
180
|
+
console.log(` â
Removed empty directory: .github/workflows`)
|
|
181
|
+
}
|
|
182
|
+
} catch {
|
|
183
|
+
// Ignore cleanup errors
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Remove .github if empty
|
|
188
|
+
if (existsSync(githubDir)) {
|
|
189
|
+
try {
|
|
190
|
+
const files = readdirSync(githubDir)
|
|
191
|
+
if (files.length === 0) {
|
|
192
|
+
rmSync(githubDir, { recursive: true })
|
|
193
|
+
console.log(` â
Removed empty directory: .github`)
|
|
194
|
+
}
|
|
195
|
+
} catch {
|
|
196
|
+
// Ignore cleanup errors
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|