inup 1.4.12 → 1.5.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/LICENSE +21 -0
- package/README.md +39 -30
- package/dist/cli.js +29 -14
- package/dist/config/project-config.js +6 -0
- package/dist/core/package-detector.js +3 -2
- package/dist/core/upgrade-runner.js +6 -3
- package/dist/features/changelog/clients/github-client.js +134 -0
- package/dist/features/changelog/clients/npm-registry-client.js +53 -0
- package/dist/features/changelog/index.js +19 -0
- package/dist/features/changelog/parsers/changelog-parser.js +68 -0
- package/dist/features/changelog/parsers/github-release-html-parser.js +61 -0
- package/dist/features/changelog/parsers/package-metadata.js +34 -0
- package/dist/features/changelog/parsers/repository-ref.js +26 -0
- package/dist/features/changelog/services/changelog-service.js +30 -0
- package/dist/features/changelog/services/package-metadata-service.js +108 -0
- package/dist/features/changelog/services/release-notes-service.js +180 -0
- package/dist/features/changelog/types/changelog.types.js +3 -0
- package/dist/interactive-ui.js +242 -114
- package/dist/services/background-audit.js +60 -0
- package/dist/services/index.js +3 -1
- package/dist/services/vulnerability-checker.js +133 -0
- package/dist/ui/controllers/index.js +8 -0
- package/dist/ui/controllers/package-info-modal-controller.js +237 -0
- package/dist/ui/controllers/vulnerability-audit-controller.js +82 -0
- package/dist/ui/index.js +3 -0
- package/dist/ui/input-handler.js +40 -9
- package/dist/ui/modal/index.js +22 -0
- package/dist/ui/modal/layout.js +84 -0
- package/dist/ui/modal/package-info-sections.js +327 -0
- package/dist/ui/modal/package-info.js +147 -0
- package/dist/ui/modal/theme-selector.js +46 -0
- package/dist/ui/modal/types.js +3 -0
- package/dist/ui/presenters/index.js +11 -0
- package/dist/ui/presenters/vulnerability.js +76 -0
- package/dist/ui/renderer/index.js +9 -11
- package/dist/ui/renderer/package-list.js +135 -62
- package/dist/ui/state/filter-manager.js +17 -2
- package/dist/ui/state/modal-manager.js +48 -6
- package/dist/ui/state/state-manager.js +42 -7
- package/dist/ui/utils/cursor.js +18 -0
- package/dist/ui/utils/index.js +8 -1
- package/dist/ui/utils/terminal-input.js +125 -0
- package/dist/ui/utils/text.js +75 -0
- package/dist/ui/utils/version.js +3 -2
- package/dist/utils/git.js +33 -0
- package/dist/utils/index.js +1 -0
- package/package.json +22 -19
- package/dist/services/changelog-fetcher.js +0 -215
- package/dist/ui/renderer/modal.js +0 -190
- package/dist/ui/renderer/theme-selector.js +0 -83
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Donfear
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,49 +1,45 @@
|
|
|
1
|
-
#
|
|
1
|
+
# inup — Interactive Dependency Upgrader
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/inup)
|
|
4
4
|
[](https://www.npmjs.com/package/inup)
|
|
5
5
|
[](https://www.npmjs.com/package/inup)
|
|
6
|
+
[](https://github.com/donfear/inup/actions/workflows/ci.yml)
|
|
7
|
+
[](https://github.com/donfear/inup/blob/main/LICENSE)
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
Interactively upgrade outdated dependencies across npm, yarn, pnpm, and bun. Auto-detects your package manager, works in monorepos and workspaces, and requires zero configuration.
|
|
8
10
|
|
|
9
11
|

|
|
10
12
|
|
|
11
|
-
##
|
|
13
|
+
## Quick Start
|
|
12
14
|
|
|
13
15
|
```bash
|
|
14
16
|
npx inup
|
|
15
17
|
```
|
|
16
18
|
|
|
17
|
-
Or install globally:
|
|
19
|
+
Or install globally with your preferred package manager:
|
|
18
20
|
|
|
19
21
|
```bash
|
|
20
22
|
npm install -g inup
|
|
23
|
+
pnpm add -g inup
|
|
24
|
+
yarn global add inup
|
|
25
|
+
bun add -g inup
|
|
21
26
|
```
|
|
22
27
|
|
|
23
|
-
|
|
28
|
+
Run `inup` in any project — it scans for outdated packages and lets you pick what to upgrade.
|
|
24
29
|
|
|
25
|
-
##
|
|
30
|
+
## Why inup?
|
|
26
31
|
|
|
27
|
-
- **
|
|
28
|
-
- **Live Toggles
|
|
29
|
-
- **Zero Config
|
|
30
|
-
- **Monorepo Ready
|
|
31
|
-
- **
|
|
32
|
+
- **All Dependencies at Once** — Dev, peer, and optional dependencies load automatically. No more re-running with `--peer` or `--dev` flags.
|
|
33
|
+
- **Live Toggles** — Filter dependency types (`d`, `p`, `o`) on the fly without restarting.
|
|
34
|
+
- **Zero Config** — Auto-detects npm, yarn, pnpm, or bun from your lockfile.
|
|
35
|
+
- **Monorepo Ready** — Discovers and upgrades across workspaces seamlessly.
|
|
36
|
+
- **Vulnerability Audit** — Flags known security vulnerabilities right in the package list so you know what's risky before upgrading.
|
|
37
|
+
- **Changelog Viewer** — Read release notes and changelogs inline without leaving the terminal.
|
|
38
|
+
- **Built-in Search** — Press `/` to filter packages instantly.
|
|
39
|
+
- **Package Details** — Press `i` to view package info, download stats, and more.
|
|
40
|
+
- **Themes** — Press `t` to switch between color themes.
|
|
32
41
|
|
|
33
|
-
##
|
|
34
|
-
|
|
35
|
-
- `↑/↓` - Navigate packages
|
|
36
|
-
- `←/→` - Select version (current, patch, minor, major)
|
|
37
|
-
- `Space` - Toggle selection
|
|
38
|
-
- `m` - Select all minor updates
|
|
39
|
-
- `l` - Select all latest updates
|
|
40
|
-
- `u` - Unselect all
|
|
41
|
-
- `/` - Search packages
|
|
42
|
-
- `t` - Change theme
|
|
43
|
-
- `i` - View package info
|
|
44
|
-
- `Enter` - Confirm and upgrade
|
|
45
|
-
|
|
46
|
-
## ⚙️ Options
|
|
42
|
+
## Options
|
|
47
43
|
|
|
48
44
|
```bash
|
|
49
45
|
inup [options]
|
|
@@ -56,12 +52,25 @@ inup [options]
|
|
|
56
52
|
--debug Write verbose debug logs
|
|
57
53
|
```
|
|
58
54
|
|
|
59
|
-
##
|
|
55
|
+
## Keyboard Shortcuts
|
|
56
|
+
|
|
57
|
+
| Key | Action |
|
|
58
|
+
|-----|--------|
|
|
59
|
+
| `↑` `↓` | Navigate packages |
|
|
60
|
+
| `←` `→` | Select version (current, patch, minor, major) |
|
|
61
|
+
| `Space` | Toggle selection |
|
|
62
|
+
| `m` | Select all minor updates |
|
|
63
|
+
| `l` | Select all latest updates |
|
|
64
|
+
| `u` | Unselect all |
|
|
65
|
+
| `/` | Search packages |
|
|
66
|
+
| `i` | View package info |
|
|
67
|
+
| `t` | Change theme |
|
|
68
|
+
| `Enter` | Confirm and upgrade |
|
|
60
69
|
|
|
61
|
-
|
|
70
|
+
## Privacy
|
|
62
71
|
|
|
63
|
-
|
|
72
|
+
No tracking, no telemetry, no data collection. Package metadata is fetched directly from the npm registry. Download counts come from the npm downloads API. When needed for exact-version manifests, inup may fetch a pinned `package.json` from jsDelivr.
|
|
64
73
|
|
|
65
|
-
##
|
|
74
|
+
## License
|
|
66
75
|
|
|
67
|
-
MIT
|
|
76
|
+
[MIT](LICENSE)
|
package/dist/cli.js
CHANGED
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
5
|
};
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.runCli = runCli;
|
|
7
8
|
const commander_1 = require("commander");
|
|
8
9
|
const chalk_1 = __importDefault(require("chalk"));
|
|
9
10
|
const fs_1 = require("fs");
|
|
@@ -12,24 +13,23 @@ const index_1 = require("./index");
|
|
|
12
13
|
const services_1 = require("./services");
|
|
13
14
|
const config_1 = require("./config");
|
|
14
15
|
const utils_1 = require("./utils");
|
|
16
|
+
const git_1 = require("./utils/git");
|
|
17
|
+
const terminal_input_1 = require("./ui/utils/terminal-input");
|
|
15
18
|
const packageJson = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../package.json'), 'utf-8'));
|
|
16
19
|
const program = new commander_1.Command();
|
|
17
|
-
|
|
18
|
-
.name('inup')
|
|
19
|
-
.description('Interactive upgrade tool for package managers. Auto-detects and works with npm, yarn, pnpm, and bun.')
|
|
20
|
-
.version(packageJson.version)
|
|
21
|
-
.option('-d, --dir <directory>', 'specify directory to run in', process.cwd())
|
|
22
|
-
.option('-e, --exclude <patterns>', 'exclude paths matching regex patterns (comma-separated)', '')
|
|
23
|
-
.option('-i, --ignore <packages>', 'ignore packages (comma-separated, supports glob patterns like @babel/*)')
|
|
24
|
-
.option('--max-depth <number>', 'maximum directory depth for package.json discovery', '10')
|
|
25
|
-
.option('--package-manager <name>', 'manually specify package manager (npm, yarn, pnpm, bun)')
|
|
26
|
-
.option('--debug', 'write verbose debug log to /tmp/inup-debug-YYYY-MM-DD.log')
|
|
27
|
-
.action(async (options) => {
|
|
28
|
-
console.log(chalk_1.default.bold.blue(`🚀 `) + chalk_1.default.bold.red(`i`) + chalk_1.default.bold.yellow(`n`) + chalk_1.default.bold.blue(`u`) + chalk_1.default.bold.magenta(`p`) + `\n`);
|
|
20
|
+
async function runCli(options) {
|
|
29
21
|
const cwd = (0, path_1.resolve)(options.dir);
|
|
30
22
|
if (options.debug || process.env.INUP_DEBUG === '1') {
|
|
31
23
|
(0, utils_1.enableDebugLogging)();
|
|
32
24
|
}
|
|
25
|
+
const gitState = (0, git_1.getGitWorkingTreeState)(cwd);
|
|
26
|
+
if (gitState.isRepo && gitState.isDirty) {
|
|
27
|
+
const shouldProceed = await terminal_input_1.TerminalInput.promptForImmediateConfirmation(`${chalk_1.default.yellow('Warning:')} dirty working tree. Proceed anyway? ${chalk_1.default.dim('[y/N]')} `, false);
|
|
28
|
+
if (!shouldProceed) {
|
|
29
|
+
console.log(chalk_1.default.yellow('Upgrade cancelled.'));
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
33
|
// Load project config from .inuprc
|
|
34
34
|
const projectConfig = (0, config_1.loadProjectConfig)(cwd);
|
|
35
35
|
// Merge CLI exclude patterns with config
|
|
@@ -73,6 +73,8 @@ program
|
|
|
73
73
|
maxDepth,
|
|
74
74
|
ignorePackages,
|
|
75
75
|
packageManager,
|
|
76
|
+
showPeerDependencyVulnerabilities: projectConfig.showPeerDependencyVulnerabilities ?? false,
|
|
77
|
+
showOptionalDependencyVulnerabilities: projectConfig.showOptionalDependencyVulnerabilities ?? false,
|
|
76
78
|
debug: options.debug || process.env.INUP_DEBUG === '1',
|
|
77
79
|
});
|
|
78
80
|
await upgrader.run();
|
|
@@ -98,7 +100,18 @@ program
|
|
|
98
100
|
console.log(chalk_1.default.yellow('└' + '─'.repeat(78) + '┘'));
|
|
99
101
|
console.log('');
|
|
100
102
|
}
|
|
101
|
-
}
|
|
103
|
+
}
|
|
104
|
+
program
|
|
105
|
+
.name('inup')
|
|
106
|
+
.description('Interactive upgrade tool for package managers. Auto-detects and works with npm, yarn, pnpm, and bun.')
|
|
107
|
+
.version(packageJson.version)
|
|
108
|
+
.option('-d, --dir <directory>', 'specify directory to run in', process.cwd())
|
|
109
|
+
.option('-e, --exclude <patterns>', 'exclude paths matching regex patterns (comma-separated)', '')
|
|
110
|
+
.option('-i, --ignore <packages>', 'ignore packages (comma-separated, supports glob patterns like @babel/*)')
|
|
111
|
+
.option('--max-depth <number>', 'maximum directory depth for package.json discovery', '10')
|
|
112
|
+
.option('--package-manager <name>', 'manually specify package manager (npm, yarn, pnpm, bun)')
|
|
113
|
+
.option('--debug', 'write verbose debug log to /tmp/inup-debug-YYYY-MM-DD.log')
|
|
114
|
+
.action(runCli);
|
|
102
115
|
// Handle uncaught errors gracefully
|
|
103
116
|
process.on('uncaughtException', (error) => {
|
|
104
117
|
console.error(chalk_1.default.red('Uncaught Exception:'), error.message);
|
|
@@ -127,5 +140,7 @@ process.on('SIGTERM', () => {
|
|
|
127
140
|
console.log(chalk_1.default.yellow('\n\nOperation cancelled.'));
|
|
128
141
|
process.exit(0);
|
|
129
142
|
});
|
|
130
|
-
|
|
143
|
+
if (require.main === module) {
|
|
144
|
+
program.parse();
|
|
145
|
+
}
|
|
131
146
|
//# sourceMappingURL=cli.js.map
|
|
@@ -49,6 +49,12 @@ function normalizeConfig(config) {
|
|
|
49
49
|
normalized.exclude = config.exclude.filter((item) => typeof item === 'string');
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
|
+
if (typeof config.showPeerDependencyVulnerabilities === 'boolean') {
|
|
53
|
+
normalized.showPeerDependencyVulnerabilities = config.showPeerDependencyVulnerabilities;
|
|
54
|
+
}
|
|
55
|
+
if (typeof config.showOptionalDependencyVulnerabilities === 'boolean') {
|
|
56
|
+
normalized.showOptionalDependencyVulnerabilities = config.showOptionalDependencyVulnerabilities;
|
|
57
|
+
}
|
|
52
58
|
return normalized;
|
|
53
59
|
}
|
|
54
60
|
/**
|
|
@@ -44,7 +44,7 @@ class PackageDetector {
|
|
|
44
44
|
constructor(options) {
|
|
45
45
|
this.packageJsonPath = null;
|
|
46
46
|
this.packageJson = null;
|
|
47
|
-
this.
|
|
47
|
+
this.batchSize = 25;
|
|
48
48
|
this.batchConcurrency = 5;
|
|
49
49
|
this.cwd = options?.cwd || process.cwd();
|
|
50
50
|
this.excludePatterns = options?.excludePatterns || [];
|
|
@@ -115,7 +115,7 @@ class PackageDetector {
|
|
|
115
115
|
},
|
|
116
116
|
});
|
|
117
117
|
}, prepared.currentVersions, {
|
|
118
|
-
|
|
118
|
+
batchSize: this.batchSize,
|
|
119
119
|
concurrency: this.batchConcurrency,
|
|
120
120
|
});
|
|
121
121
|
utils_3.debugLog.perf('PackageDetector', `registry fetch (${resolved}/${prepared.uniquePackages.length} resolved)`, tFetch);
|
|
@@ -245,6 +245,7 @@ class PackageDetector {
|
|
|
245
245
|
isOutdated,
|
|
246
246
|
hasRangeUpdate,
|
|
247
247
|
hasMajorUpdate,
|
|
248
|
+
allVersions,
|
|
248
249
|
};
|
|
249
250
|
}
|
|
250
251
|
catch (error) {
|
|
@@ -9,6 +9,7 @@ const package_detector_1 = require("./package-detector");
|
|
|
9
9
|
const interactive_ui_1 = require("../interactive-ui");
|
|
10
10
|
const upgrader_1 = require("./upgrader");
|
|
11
11
|
const package_manager_detector_1 = require("../services/package-manager-detector");
|
|
12
|
+
const utils_1 = require("../ui/utils");
|
|
12
13
|
/**
|
|
13
14
|
* Main orchestrator for the inup upgrade process
|
|
14
15
|
*/
|
|
@@ -24,7 +25,10 @@ class UpgradeRunner {
|
|
|
24
25
|
this.packageManager = package_manager_detector_1.PackageManagerDetector.detect(cwd);
|
|
25
26
|
}
|
|
26
27
|
this.detector = new package_detector_1.PackageDetector(options);
|
|
27
|
-
this.ui = new interactive_ui_1.InteractiveUI(this.packageManager
|
|
28
|
+
this.ui = new interactive_ui_1.InteractiveUI(this.packageManager, {
|
|
29
|
+
showPeerDependencyVulnerabilities: options?.showPeerDependencyVulnerabilities ?? false,
|
|
30
|
+
showOptionalDependencyVulnerabilities: options?.showOptionalDependencyVulnerabilities ?? false,
|
|
31
|
+
});
|
|
28
32
|
this.upgrader = new upgrader_1.PackageUpgrader(this.packageManager);
|
|
29
33
|
}
|
|
30
34
|
async run() {
|
|
@@ -114,8 +118,7 @@ class UpgradeRunner {
|
|
|
114
118
|
shouldProceed = await this.ui.confirmUpgrade(selectedChoices);
|
|
115
119
|
if (shouldProceed === null) {
|
|
116
120
|
// User pressed N or ESC - go back to selection with current selections preserved
|
|
117
|
-
|
|
118
|
-
console.log(chalk_1.default.bold.blue('🚀 inup\n'));
|
|
121
|
+
utils_1.ConsoleUtils.clearProgress();
|
|
119
122
|
selectedChoices = progress.isLoading
|
|
120
123
|
? await this.ui.selectPackagesToUpgradeProgressive(selectionStates, progress, (refresh) => {
|
|
121
124
|
refreshUI = refresh;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GitHubClient = void 0;
|
|
4
|
+
const repository_ref_1 = require("../parsers/repository-ref");
|
|
5
|
+
const GITHUB_RELEASES_PAGE_LIMIT = 3;
|
|
6
|
+
class GitHubClient {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.releasesCache = new Map();
|
|
9
|
+
this.rawChangelogCache = new Map();
|
|
10
|
+
}
|
|
11
|
+
clearCache() {
|
|
12
|
+
this.releasesCache.clear();
|
|
13
|
+
this.rawChangelogCache.clear();
|
|
14
|
+
}
|
|
15
|
+
async fetchReleaseByTag(repoUrl, tag, signal) {
|
|
16
|
+
const repo = (0, repository_ref_1.parseGitHubRepo)(repoUrl);
|
|
17
|
+
if (!repo)
|
|
18
|
+
return null;
|
|
19
|
+
try {
|
|
20
|
+
const response = await fetch(`https://api.github.com/repos/${repo.owner}/${repo.repo}/releases/tags/${tag}`, {
|
|
21
|
+
method: 'GET',
|
|
22
|
+
headers: {
|
|
23
|
+
accept: 'application/vnd.github.v3+json',
|
|
24
|
+
'user-agent': 'inup-cli',
|
|
25
|
+
},
|
|
26
|
+
signal,
|
|
27
|
+
});
|
|
28
|
+
if (!response.ok)
|
|
29
|
+
return null;
|
|
30
|
+
const data = (await response.json());
|
|
31
|
+
return data.body?.trim() ? data.body.trim() : null;
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
if (error instanceof DOMException && error.name === 'AbortError') {
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async fetchReleasePageHtml(repoUrl, tag, signal) {
|
|
41
|
+
const repo = (0, repository_ref_1.parseGitHubRepo)(repoUrl);
|
|
42
|
+
if (!repo)
|
|
43
|
+
return null;
|
|
44
|
+
try {
|
|
45
|
+
const response = await fetch(`https://github.com/${repo.owner}/${repo.repo}/releases/tag/${tag}`, {
|
|
46
|
+
method: 'GET',
|
|
47
|
+
signal,
|
|
48
|
+
});
|
|
49
|
+
if (!response.ok)
|
|
50
|
+
return null;
|
|
51
|
+
return await response.text();
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
if (error instanceof DOMException && error.name === 'AbortError') {
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async fetchReleases(repoUrl, signal) {
|
|
61
|
+
const repo = (0, repository_ref_1.parseGitHubRepo)(repoUrl);
|
|
62
|
+
if (!repo)
|
|
63
|
+
return null;
|
|
64
|
+
const cacheKey = `${repo.owner}/${repo.repo}`;
|
|
65
|
+
if (this.releasesCache.has(cacheKey)) {
|
|
66
|
+
return this.releasesCache.get(cacheKey);
|
|
67
|
+
}
|
|
68
|
+
const releases = [];
|
|
69
|
+
for (let page = 1; page <= GITHUB_RELEASES_PAGE_LIMIT; page += 1) {
|
|
70
|
+
try {
|
|
71
|
+
const response = await fetch(`https://api.github.com/repos/${repo.owner}/${repo.repo}/releases?per_page=100&page=${page}`, {
|
|
72
|
+
method: 'GET',
|
|
73
|
+
headers: {
|
|
74
|
+
accept: 'application/vnd.github.v3+json',
|
|
75
|
+
'user-agent': 'inup-cli',
|
|
76
|
+
},
|
|
77
|
+
signal,
|
|
78
|
+
});
|
|
79
|
+
if (!response.ok)
|
|
80
|
+
break;
|
|
81
|
+
const pageReleases = (await response.json());
|
|
82
|
+
if (!Array.isArray(pageReleases) || pageReleases.length === 0)
|
|
83
|
+
break;
|
|
84
|
+
releases.push(...pageReleases);
|
|
85
|
+
if (pageReleases.length < 100)
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
if (error instanceof DOMException && error.name === 'AbortError') {
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const result = releases.length > 0 ? releases : null;
|
|
96
|
+
this.releasesCache.set(cacheKey, result);
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
async fetchRawChangelog(repoUrl, signal) {
|
|
100
|
+
const repo = (0, repository_ref_1.parseGitHubRepo)(repoUrl);
|
|
101
|
+
if (!repo)
|
|
102
|
+
return null;
|
|
103
|
+
const cacheKey = `${repo.owner}/${repo.repo}`;
|
|
104
|
+
if (this.rawChangelogCache.has(cacheKey)) {
|
|
105
|
+
return this.rawChangelogCache.get(cacheKey);
|
|
106
|
+
}
|
|
107
|
+
const branches = ['main', 'master'];
|
|
108
|
+
const filenames = ['CHANGELOG.md', 'CHANGES.md', 'HISTORY.md'];
|
|
109
|
+
for (const branch of branches) {
|
|
110
|
+
for (const filename of filenames) {
|
|
111
|
+
try {
|
|
112
|
+
const response = await fetch(`https://raw.githubusercontent.com/${repo.owner}/${repo.repo}/${branch}/${filename}`, {
|
|
113
|
+
method: 'GET',
|
|
114
|
+
signal,
|
|
115
|
+
});
|
|
116
|
+
if (response.ok) {
|
|
117
|
+
const text = await response.text();
|
|
118
|
+
this.rawChangelogCache.set(cacheKey, text);
|
|
119
|
+
return text;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
if (error instanceof DOMException && error.name === 'AbortError') {
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
this.rawChangelogCache.set(cacheKey, null);
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
exports.GitHubClient = GitHubClient;
|
|
134
|
+
//# sourceMappingURL=github-client.js.map
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NpmRegistryClient = void 0;
|
|
4
|
+
const constants_1 = require("../../../config/constants");
|
|
5
|
+
class NpmRegistryClient {
|
|
6
|
+
async fetchPackageManifest(packageName, version, signal) {
|
|
7
|
+
try {
|
|
8
|
+
const response = await fetch(`${constants_1.NPM_REGISTRY_URL}/${encodeURIComponent(packageName)}/${encodeURIComponent(version)}`, {
|
|
9
|
+
method: 'GET',
|
|
10
|
+
headers: {
|
|
11
|
+
accept: 'application/json',
|
|
12
|
+
},
|
|
13
|
+
signal,
|
|
14
|
+
});
|
|
15
|
+
if (!response.ok) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
return (await response.json());
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
if (error instanceof DOMException && error.name === 'AbortError') {
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async fetchDownloadStats(packageName, signal) {
|
|
28
|
+
try {
|
|
29
|
+
const response = await fetch(`https://api.npmjs.org/downloads/point/last-week/${encodeURIComponent(packageName)}`, {
|
|
30
|
+
method: 'GET',
|
|
31
|
+
headers: {
|
|
32
|
+
accept: 'application/json',
|
|
33
|
+
},
|
|
34
|
+
signal,
|
|
35
|
+
});
|
|
36
|
+
if (!response.ok) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
const data = (await response.json());
|
|
40
|
+
return {
|
|
41
|
+
downloads: data.downloads || 0,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
if (error instanceof DOMException && error.name === 'AbortError') {
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.NpmRegistryClient = NpmRegistryClient;
|
|
53
|
+
//# sourceMappingURL=npm-registry-client.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./types/changelog.types"), exports);
|
|
18
|
+
__exportStar(require("./services/changelog-service"), exports);
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.normalizeReleaseTag = normalizeReleaseTag;
|
|
37
|
+
exports.extractVersionSection = extractVersionSection;
|
|
38
|
+
const semver = __importStar(require("semver"));
|
|
39
|
+
function normalizeReleaseTag(tagName) {
|
|
40
|
+
if (!tagName)
|
|
41
|
+
return null;
|
|
42
|
+
const cleanedTag = semver.clean(tagName);
|
|
43
|
+
if (cleanedTag)
|
|
44
|
+
return cleanedTag;
|
|
45
|
+
const semverMatch = tagName.match(/\d+\.\d+\.\d+(?:-[0-9A-Za-z-.]+)?(?:\+[0-9A-Za-z-.]+)?/);
|
|
46
|
+
if (!semverMatch)
|
|
47
|
+
return null;
|
|
48
|
+
return semver.clean(semverMatch[0]);
|
|
49
|
+
}
|
|
50
|
+
function extractVersionSection(changelog, version) {
|
|
51
|
+
const escapedVersion = version.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
52
|
+
const sectionRegex = new RegExp(`^##\\s+\\[?v?${escapedVersion}\\]?[^\\n]*\\n`, 'm');
|
|
53
|
+
const match = sectionRegex.exec(changelog);
|
|
54
|
+
if (!match)
|
|
55
|
+
return null;
|
|
56
|
+
const startIndex = match.index + match[0].length;
|
|
57
|
+
const nextSectionMatch = /^## /m.exec(changelog.slice(startIndex));
|
|
58
|
+
const endIndex = nextSectionMatch ? startIndex + nextSectionMatch.index : changelog.length;
|
|
59
|
+
const section = changelog.slice(startIndex, endIndex).trim();
|
|
60
|
+
if (section.length === 0)
|
|
61
|
+
return null;
|
|
62
|
+
const lines = section.split('\n');
|
|
63
|
+
if (lines.length > 100) {
|
|
64
|
+
return `${lines.slice(0, 100).join('\n')}\n...`;
|
|
65
|
+
}
|
|
66
|
+
return section;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=changelog-parser.js.map
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractReleaseNotesFromHtml = extractReleaseNotesFromHtml;
|
|
4
|
+
function extractReleaseNotesFromHtml(html) {
|
|
5
|
+
const bodyContentIndex = html.indexOf('data-test-selector="body-content"');
|
|
6
|
+
if (bodyContentIndex === -1)
|
|
7
|
+
return null;
|
|
8
|
+
const markdownBodyIndex = html.indexOf('class="markdown-body', bodyContentIndex);
|
|
9
|
+
if (markdownBodyIndex === -1)
|
|
10
|
+
return null;
|
|
11
|
+
const contentStart = html.indexOf('>', markdownBodyIndex);
|
|
12
|
+
if (contentStart === -1)
|
|
13
|
+
return null;
|
|
14
|
+
let depth = 1;
|
|
15
|
+
let cursor = contentStart + 1;
|
|
16
|
+
while (depth > 0 && cursor < html.length) {
|
|
17
|
+
const nextOpen = html.indexOf('<div', cursor);
|
|
18
|
+
const nextClose = html.indexOf('</div>', cursor);
|
|
19
|
+
if (nextClose === -1)
|
|
20
|
+
return null;
|
|
21
|
+
if (nextOpen !== -1 && nextOpen < nextClose) {
|
|
22
|
+
depth += 1;
|
|
23
|
+
cursor = nextOpen + 4;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
depth -= 1;
|
|
27
|
+
cursor = nextClose + 6;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (depth !== 0)
|
|
31
|
+
return null;
|
|
32
|
+
const normalized = html
|
|
33
|
+
.slice(contentStart + 1, cursor - 6)
|
|
34
|
+
.replace(/<svg[\s\S]*?<\/svg>/g, '')
|
|
35
|
+
.replace(/<h([1-6])[^>]*>/g, (_full, level) => `${'#'.repeat(Number(level))} `)
|
|
36
|
+
.replace(/<\/h[1-6]>/g, '\n\n')
|
|
37
|
+
.replace(/<li[^>]*>/g, '- ')
|
|
38
|
+
.replace(/<\/li>/g, '\n')
|
|
39
|
+
.replace(/<p[^>]*>/g, '')
|
|
40
|
+
.replace(/<\/p>/g, '\n\n')
|
|
41
|
+
.replace(/<br\s*\/?>/g, '\n')
|
|
42
|
+
.replace(/<a\b[^>]*>([\s\S]*?)<\/a>/g, '$1')
|
|
43
|
+
.replace(/<strong[^>]*>([\s\S]*?)<\/strong>/g, '**$1**')
|
|
44
|
+
.replace(/<code[^>]*>([\s\S]*?)<\/code>/g, '`$1`')
|
|
45
|
+
.replace(/<[^>]+>/g, '');
|
|
46
|
+
const decoded = normalized
|
|
47
|
+
.replace(/&/g, '&')
|
|
48
|
+
.replace(/</g, '<')
|
|
49
|
+
.replace(/>/g, '>')
|
|
50
|
+
.replace(/"/g, '"')
|
|
51
|
+
.replace(/'/g, "'")
|
|
52
|
+
.replace(/ /g, ' ');
|
|
53
|
+
const cleaned = decoded
|
|
54
|
+
.split('\n')
|
|
55
|
+
.map((line) => line.trimEnd())
|
|
56
|
+
.join('\n')
|
|
57
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
58
|
+
.trim();
|
|
59
|
+
return cleaned.length > 0 ? cleaned : null;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=github-release-html-parser.js.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mapPackageManifestToMetadata = mapPackageManifestToMetadata;
|
|
4
|
+
const repository_ref_1 = require("./repository-ref");
|
|
5
|
+
function mapPackageManifestToMetadata(packageName, rawData) {
|
|
6
|
+
const repository = rawData.repository;
|
|
7
|
+
const bugs = rawData.bugs;
|
|
8
|
+
const keywords = Array.isArray(rawData.keywords) ? rawData.keywords : [];
|
|
9
|
+
const author = typeof rawData.author === 'object' && rawData.author !== null
|
|
10
|
+
? (rawData.author.name ?? rawData.author)
|
|
11
|
+
: rawData.author;
|
|
12
|
+
const repositoryUrl = (0, repository_ref_1.extractRepositoryUrl)(repository?.url || '');
|
|
13
|
+
const npmUrl = `https://www.npmjs.com/package/${encodeURIComponent(packageName)}`;
|
|
14
|
+
const issuesUrl = repositoryUrl ? `${repositoryUrl}/issues` : undefined;
|
|
15
|
+
const metadata = {
|
|
16
|
+
description: typeof rawData.description === 'string' && rawData.description
|
|
17
|
+
? rawData.description
|
|
18
|
+
: 'No description available',
|
|
19
|
+
homepage: typeof rawData.homepage === 'string' ? rawData.homepage : undefined,
|
|
20
|
+
repository,
|
|
21
|
+
bugs,
|
|
22
|
+
keywords,
|
|
23
|
+
author: typeof author === 'string' ? author : undefined,
|
|
24
|
+
license: typeof rawData.license === 'string' ? rawData.license : undefined,
|
|
25
|
+
repositoryUrl,
|
|
26
|
+
npmUrl,
|
|
27
|
+
issuesUrl,
|
|
28
|
+
};
|
|
29
|
+
if (repositoryUrl) {
|
|
30
|
+
metadata.releaseNotes = `${repositoryUrl}/releases`;
|
|
31
|
+
}
|
|
32
|
+
return metadata;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=package-metadata.js.map
|