itty-packager 1.2.0 โ 1.6.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/.claude/settings.local.json +2 -1
- package/lib/commands/publish.js +170 -67
- package/package.json +1 -1
package/lib/commands/publish.js
CHANGED
|
@@ -2,7 +2,6 @@ import { parseArgs } from 'node:util'
|
|
|
2
2
|
import { spawn } from 'node:child_process'
|
|
3
3
|
import fs from 'fs-extra'
|
|
4
4
|
import path from 'node:path'
|
|
5
|
-
import readline from 'node:readline'
|
|
6
5
|
import { prepareCommand } from './prepare.js'
|
|
7
6
|
|
|
8
7
|
const SEMVER_TYPES = ['major', 'minor', 'patch']
|
|
@@ -79,41 +78,122 @@ async function getCommitMessage(newVersion, silent = false) {
|
|
|
79
78
|
return `released v${newVersion}`
|
|
80
79
|
}
|
|
81
80
|
|
|
82
|
-
return new Promise((resolve) => {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
console.log('\nEnter optional commit message (empty submission skips):')
|
|
89
|
-
console.log('\x1b[90mPress Enter to finish, Ctrl+C to skip\x1b[0m')
|
|
90
|
-
process.stdout.write('\n')
|
|
91
|
-
|
|
81
|
+
return new Promise((resolve, reject) => {
|
|
82
|
+
// Show placeholder with hidden cursor
|
|
83
|
+
const placeholderText = '\x1b[90mpress enter to skip\x1b[0m'
|
|
84
|
+
process.stdout.write(`๐ฌ Commit message: ${placeholderText}\x1b[?25l`) // Hide cursor
|
|
85
|
+
|
|
92
86
|
let inputLines = []
|
|
93
87
|
let firstInput = true
|
|
88
|
+
let placeholderCleared = false
|
|
89
|
+
let inputBuffer = ''
|
|
90
|
+
|
|
91
|
+
// Set up raw mode for immediate key detection
|
|
92
|
+
process.stdin.setRawMode(true)
|
|
93
|
+
process.stdin.resume()
|
|
94
|
+
|
|
95
|
+
const clearPlaceholder = () => {
|
|
96
|
+
if (!placeholderCleared) {
|
|
97
|
+
// Clear line and show prompt with cursor
|
|
98
|
+
process.stdout.write('\r\x1b[K๐ฌ Commit message: \x1b[?25h') // Show cursor
|
|
99
|
+
placeholderCleared = true
|
|
100
|
+
}
|
|
101
|
+
}
|
|
94
102
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
103
|
+
const handleInput = (chunk) => {
|
|
104
|
+
const key = chunk.toString()
|
|
105
|
+
|
|
106
|
+
// Check for escape sequences
|
|
107
|
+
if (key === '\x1b') {
|
|
108
|
+
// Wait for potential escape sequence completion
|
|
109
|
+
setTimeout(() => {
|
|
110
|
+
process.stdout.write('\r\x1b[K๐ฌ Commit message: cancelled\x1b[?25h\n')
|
|
111
|
+
cleanup()
|
|
112
|
+
reject(new Error('User cancelled with Escape key'))
|
|
113
|
+
}, 10)
|
|
100
114
|
return
|
|
101
115
|
}
|
|
102
116
|
|
|
103
|
-
|
|
117
|
+
// Handle Ctrl+C
|
|
118
|
+
if (key === '\x03') {
|
|
119
|
+
process.stdout.write('\r\x1b[K๐ฌ Commit message: cancelled\x1b[?25h\n')
|
|
120
|
+
cleanup()
|
|
121
|
+
reject(new Error('User cancelled with Ctrl+C'))
|
|
122
|
+
return
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Handle Enter
|
|
126
|
+
if (key === '\r' || key === '\n') {
|
|
127
|
+
if (!placeholderCleared && inputBuffer === '') {
|
|
128
|
+
// Empty input, skip
|
|
129
|
+
process.stdout.write('\r\x1b[K๐ฌ Commit message: \x1b[?25h\n')
|
|
130
|
+
cleanup()
|
|
131
|
+
resolve(`released v${newVersion}`)
|
|
132
|
+
return
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Single line input - finish immediately
|
|
136
|
+
if (firstInput) {
|
|
137
|
+
const customMessage = inputBuffer.trim()
|
|
138
|
+
process.stdout.write('\x1b[?25h\n')
|
|
139
|
+
cleanup()
|
|
140
|
+
|
|
141
|
+
if (!customMessage) {
|
|
142
|
+
resolve(`released v${newVersion}`)
|
|
143
|
+
} else {
|
|
144
|
+
const escapedMessage = customMessage.replace(/"/g, '\\"')
|
|
145
|
+
resolve(`released v${newVersion} - ${escapedMessage}`)
|
|
146
|
+
}
|
|
147
|
+
return
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Multi-line: empty line finishes input
|
|
151
|
+
if (inputBuffer.trim() === '') {
|
|
152
|
+
finishInput()
|
|
153
|
+
return
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Add line and continue
|
|
157
|
+
inputLines.push(inputBuffer)
|
|
158
|
+
inputBuffer = ''
|
|
159
|
+
firstInput = false
|
|
160
|
+
process.stdout.write('\n')
|
|
161
|
+
return
|
|
162
|
+
}
|
|
104
163
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
164
|
+
// Handle backspace
|
|
165
|
+
if (key === '\x7f' || key === '\x08') {
|
|
166
|
+
if (!placeholderCleared) return // Can't backspace in placeholder
|
|
167
|
+
|
|
168
|
+
if (inputBuffer.length > 0) {
|
|
169
|
+
inputBuffer = inputBuffer.slice(0, -1)
|
|
170
|
+
process.stdout.write('\b \b')
|
|
171
|
+
}
|
|
108
172
|
return
|
|
109
173
|
}
|
|
110
174
|
|
|
111
|
-
|
|
112
|
-
|
|
175
|
+
// Handle printable characters
|
|
176
|
+
if (key.length === 1 && key >= ' ' && key <= '~') {
|
|
177
|
+
if (!placeholderCleared) {
|
|
178
|
+
clearPlaceholder()
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
inputBuffer += key
|
|
182
|
+
process.stdout.write(key)
|
|
183
|
+
return
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const cleanup = () => {
|
|
188
|
+
process.stdin.setRawMode(false)
|
|
189
|
+
process.stdin.pause()
|
|
190
|
+
process.stdin.removeListener('data', handleInput)
|
|
191
|
+
}
|
|
113
192
|
|
|
114
193
|
const finishInput = () => {
|
|
115
|
-
rl.close()
|
|
116
194
|
const customMessage = inputLines.join('\n').trim()
|
|
195
|
+
process.stdout.write('\x1b[?25h\n') // Show cursor and newline
|
|
196
|
+
cleanup()
|
|
117
197
|
|
|
118
198
|
if (!customMessage) {
|
|
119
199
|
resolve(`released v${newVersion}`)
|
|
@@ -124,18 +204,7 @@ async function getCommitMessage(newVersion, silent = false) {
|
|
|
124
204
|
}
|
|
125
205
|
}
|
|
126
206
|
|
|
127
|
-
|
|
128
|
-
console.log('\nSkipped. Using default commit message.')
|
|
129
|
-
rl.close()
|
|
130
|
-
resolve(`released v${newVersion}`)
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
// Handle Ctrl+D (EOF) as completion
|
|
134
|
-
rl.on('close', () => {
|
|
135
|
-
if (!firstInput && inputLines.length > 0) {
|
|
136
|
-
finishInput()
|
|
137
|
-
}
|
|
138
|
-
})
|
|
207
|
+
process.stdin.on('data', handleInput)
|
|
139
208
|
})
|
|
140
209
|
}
|
|
141
210
|
|
|
@@ -283,10 +352,14 @@ Publish Options:
|
|
|
283
352
|
|
|
284
353
|
Git Options:
|
|
285
354
|
--tag Create git tag for release
|
|
286
|
-
--push Push changes and tags to git remote
|
|
355
|
+
--push Push changes and tags to git remote (prompts for commit message)
|
|
287
356
|
--no-git Skip all git operations
|
|
288
357
|
-h, --help Show help
|
|
289
358
|
|
|
359
|
+
Interactive Options:
|
|
360
|
+
When using --push, you'll be prompted for an optional commit message.
|
|
361
|
+
Press Enter to skip, Escape or Ctrl+C to cancel and revert version.
|
|
362
|
+
|
|
290
363
|
Examples:
|
|
291
364
|
itty publish # Patch version bump and publish from dist/ (default)
|
|
292
365
|
itty publish --minor --tag # Minor bump, publish, and create git tag
|
|
@@ -327,6 +400,12 @@ This creates a clean, flat package structure in node_modules.
|
|
|
327
400
|
const silent = publishArgs.silent
|
|
328
401
|
const verbose = publishArgs.verbose
|
|
329
402
|
|
|
403
|
+
// Read package.json and store original version for potential revert
|
|
404
|
+
const pkgPath = path.join(rootPath, 'package.json')
|
|
405
|
+
const originalPkg = await fs.readJSON(pkgPath)
|
|
406
|
+
const originalVersion = originalPkg.version
|
|
407
|
+
const newVersion = versionBump(originalVersion, releaseType)
|
|
408
|
+
|
|
330
409
|
try {
|
|
331
410
|
// Run prepare if requested
|
|
332
411
|
if (shouldPrepare) {
|
|
@@ -334,12 +413,8 @@ This creates a clean, flat package structure in node_modules.
|
|
|
334
413
|
await prepareCommand(verbose ? ['--verbose'] : [])
|
|
335
414
|
console.log('โ
Prepare completed successfully\n')
|
|
336
415
|
}
|
|
337
|
-
// Read package.json
|
|
338
|
-
const pkgPath = path.join(rootPath, 'package.json')
|
|
339
|
-
const pkg = await fs.readJSON(pkgPath)
|
|
340
|
-
const newVersion = versionBump(pkg.version, releaseType)
|
|
341
416
|
|
|
342
|
-
console.log(`๐ฆ Publishing ${
|
|
417
|
+
console.log(`๐ฆ Publishing ${originalPkg.name} v${originalVersion} โ v${newVersion}`)
|
|
343
418
|
if (verbose) console.log(`๐ Source: ${publishArgs.src}/`)
|
|
344
419
|
|
|
345
420
|
// Check if source directory exists
|
|
@@ -396,43 +471,40 @@ This creates a clean, flat package structure in node_modules.
|
|
|
396
471
|
|
|
397
472
|
// Update package.json in temp directory with transformed paths
|
|
398
473
|
const updatedPkg = isRootPublish
|
|
399
|
-
? { ...
|
|
400
|
-
: transformPackageExports({ ...
|
|
474
|
+
? { ...originalPkg, version: newVersion } // No path transformation for root publishing
|
|
475
|
+
: transformPackageExports({ ...originalPkg, version: newVersion }, publishArgs.src)
|
|
401
476
|
const tempPkgPath = path.join(tempDir, 'package.json')
|
|
402
477
|
|
|
403
478
|
const transformMessage = isRootPublish ? '' : ' (transforming paths)'
|
|
404
479
|
if (verbose) console.log(`๐ Updating package.json to v${newVersion}${transformMessage}`)
|
|
405
480
|
await fs.writeJSON(tempPkgPath, updatedPkg, { spaces: 2 })
|
|
406
481
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
} else {
|
|
410
|
-
// Publish from temp directory
|
|
411
|
-
console.log(`๐ Publishing to npm...`)
|
|
412
|
-
|
|
413
|
-
const publishCmd = [
|
|
414
|
-
'npm publish',
|
|
415
|
-
publicAccess ? '--access=public' : '',
|
|
416
|
-
SEMVER_TYPES.includes(releaseType) ? '' : `--tag=${releaseType}`
|
|
417
|
-
].filter(Boolean).join(' ')
|
|
418
|
-
|
|
419
|
-
if (verbose) console.log(`Running: ${publishCmd}`)
|
|
420
|
-
await runCommand(publishCmd, tempDir, verbose)
|
|
421
|
-
|
|
422
|
-
// Update root package.json
|
|
482
|
+
// Update root package.json first (before git operations)
|
|
483
|
+
if (!dryRun) {
|
|
423
484
|
if (verbose) console.log(`๐ Updating root package.json`)
|
|
424
485
|
await fs.writeJSON(pkgPath, updatedPkg, { spaces: 2 })
|
|
425
486
|
}
|
|
426
487
|
|
|
427
|
-
// Git operations
|
|
488
|
+
// Git operations (before publishing)
|
|
428
489
|
if (!noGit && !dryRun) {
|
|
429
490
|
if (shouldPush || shouldTag) {
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
491
|
+
try {
|
|
492
|
+
// Get commit message (interactive or default)
|
|
493
|
+
const commitMessage = await getCommitMessage(newVersion, silent)
|
|
494
|
+
|
|
495
|
+
if (verbose) console.log(`๐ Committing changes...`)
|
|
496
|
+
await runCommand('git add .', rootPath, verbose)
|
|
497
|
+
await runCommand(`git commit -m "${commitMessage}"`, rootPath, verbose)
|
|
498
|
+
} catch (error) {
|
|
499
|
+
if (error.message.includes('cancelled')) {
|
|
500
|
+
console.log('๐ Commit cancelled - reverting version and exiting')
|
|
501
|
+
// Revert the version we just updated
|
|
502
|
+
await fs.writeJSON(pkgPath, originalPkg, { spaces: 2 })
|
|
503
|
+
// Don't rethrow - exit cleanly since this is user-initiated
|
|
504
|
+
process.exit(0)
|
|
505
|
+
}
|
|
506
|
+
throw error
|
|
507
|
+
}
|
|
436
508
|
}
|
|
437
509
|
|
|
438
510
|
if (shouldTag) {
|
|
@@ -451,17 +523,48 @@ This creates a clean, flat package structure in node_modules.
|
|
|
451
523
|
}
|
|
452
524
|
}
|
|
453
525
|
|
|
526
|
+
// NPM publish as final step
|
|
527
|
+
if (dryRun) {
|
|
528
|
+
console.log('๐งช Dry run - skipping publish')
|
|
529
|
+
} else {
|
|
530
|
+
// Publish from temp directory
|
|
531
|
+
console.log(`๐ Publishing to npm...`)
|
|
532
|
+
|
|
533
|
+
const publishCmd = [
|
|
534
|
+
'npm publish',
|
|
535
|
+
publicAccess ? '--access=public' : '',
|
|
536
|
+
SEMVER_TYPES.includes(releaseType) ? '' : `--tag=${releaseType}`
|
|
537
|
+
].filter(Boolean).join(' ')
|
|
538
|
+
|
|
539
|
+
if (verbose) console.log(`Running: ${publishCmd}`)
|
|
540
|
+
await runCommand(publishCmd, tempDir, verbose)
|
|
541
|
+
}
|
|
542
|
+
|
|
454
543
|
// Cleanup
|
|
455
544
|
if (!noCleanup) {
|
|
456
545
|
if (verbose) console.log(`๐งน Cleaning up ${publishArgs.dest}/`)
|
|
457
546
|
await fs.remove(tempDir)
|
|
458
547
|
}
|
|
459
548
|
|
|
460
|
-
console.log(`โ
Successfully published ${
|
|
549
|
+
console.log(`โ
Successfully published ${originalPkg.name}@${newVersion}`)
|
|
461
550
|
|
|
462
551
|
} catch (error) {
|
|
463
552
|
console.error(`โ Publish failed: ${error.message}`)
|
|
464
553
|
|
|
554
|
+
// Revert version in root package.json if it was changed
|
|
555
|
+
if (!dryRun) {
|
|
556
|
+
try {
|
|
557
|
+
const currentPkg = await fs.readJSON(pkgPath)
|
|
558
|
+
if (currentPkg.version !== originalVersion) {
|
|
559
|
+
if (verbose) console.log(`๐ Reverting version from v${currentPkg.version} to v${originalVersion}`)
|
|
560
|
+
await fs.writeJSON(pkgPath, { ...currentPkg, version: originalVersion }, { spaces: 2 })
|
|
561
|
+
console.log(`โ
Version reverted to v${originalVersion}`)
|
|
562
|
+
}
|
|
563
|
+
} catch (revertError) {
|
|
564
|
+
console.error(`โ Failed to revert version: ${revertError.message}`)
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
465
568
|
// Cleanup on error
|
|
466
569
|
if (await fs.pathExists(tempDir) && !noCleanup) {
|
|
467
570
|
await fs.remove(tempDir)
|