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.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +39 -30
  3. package/dist/cli.js +29 -14
  4. package/dist/config/project-config.js +6 -0
  5. package/dist/core/package-detector.js +3 -2
  6. package/dist/core/upgrade-runner.js +6 -3
  7. package/dist/features/changelog/clients/github-client.js +134 -0
  8. package/dist/features/changelog/clients/npm-registry-client.js +53 -0
  9. package/dist/features/changelog/index.js +19 -0
  10. package/dist/features/changelog/parsers/changelog-parser.js +68 -0
  11. package/dist/features/changelog/parsers/github-release-html-parser.js +61 -0
  12. package/dist/features/changelog/parsers/package-metadata.js +34 -0
  13. package/dist/features/changelog/parsers/repository-ref.js +26 -0
  14. package/dist/features/changelog/services/changelog-service.js +30 -0
  15. package/dist/features/changelog/services/package-metadata-service.js +108 -0
  16. package/dist/features/changelog/services/release-notes-service.js +180 -0
  17. package/dist/features/changelog/types/changelog.types.js +3 -0
  18. package/dist/interactive-ui.js +242 -114
  19. package/dist/services/background-audit.js +60 -0
  20. package/dist/services/index.js +3 -1
  21. package/dist/services/vulnerability-checker.js +133 -0
  22. package/dist/ui/controllers/index.js +8 -0
  23. package/dist/ui/controllers/package-info-modal-controller.js +237 -0
  24. package/dist/ui/controllers/vulnerability-audit-controller.js +82 -0
  25. package/dist/ui/index.js +3 -0
  26. package/dist/ui/input-handler.js +40 -9
  27. package/dist/ui/modal/index.js +22 -0
  28. package/dist/ui/modal/layout.js +84 -0
  29. package/dist/ui/modal/package-info-sections.js +327 -0
  30. package/dist/ui/modal/package-info.js +147 -0
  31. package/dist/ui/modal/theme-selector.js +46 -0
  32. package/dist/ui/modal/types.js +3 -0
  33. package/dist/ui/presenters/index.js +11 -0
  34. package/dist/ui/presenters/vulnerability.js +76 -0
  35. package/dist/ui/renderer/index.js +9 -11
  36. package/dist/ui/renderer/package-list.js +135 -62
  37. package/dist/ui/state/filter-manager.js +17 -2
  38. package/dist/ui/state/modal-manager.js +48 -6
  39. package/dist/ui/state/state-manager.js +42 -7
  40. package/dist/ui/utils/cursor.js +18 -0
  41. package/dist/ui/utils/index.js +8 -1
  42. package/dist/ui/utils/terminal-input.js +125 -0
  43. package/dist/ui/utils/text.js +75 -0
  44. package/dist/ui/utils/version.js +3 -2
  45. package/dist/utils/git.js +33 -0
  46. package/dist/utils/index.js +1 -0
  47. package/package.json +22 -19
  48. package/dist/services/changelog-fetcher.js +0 -215
  49. package/dist/ui/renderer/modal.js +0 -190
  50. package/dist/ui/renderer/theme-selector.js +0 -83
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractRepositoryUrl = extractRepositoryUrl;
4
+ exports.parseGitHubRepo = parseGitHubRepo;
5
+ function extractRepositoryUrl(repoUrl) {
6
+ if (!repoUrl)
7
+ return '';
8
+ let cleanUrl = repoUrl
9
+ .replace(/^git\+/, '')
10
+ .replace(/\.git$/, '')
11
+ .replace(/^github:/, 'https://github.com/');
12
+ if (!cleanUrl.startsWith('http')) {
13
+ cleanUrl = `https://github.com/${cleanUrl}`;
14
+ }
15
+ return cleanUrl;
16
+ }
17
+ function parseGitHubRepo(repoUrl) {
18
+ const match = repoUrl.match(/github\.com\/([^/]+)\/([^/]+)/);
19
+ if (!match)
20
+ return null;
21
+ return {
22
+ owner: match[1],
23
+ repo: match[2],
24
+ };
25
+ }
26
+ //# sourceMappingURL=repository-ref.js.map
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.changelogFetcher = exports.ChangelogFetcher = void 0;
4
+ const package_metadata_service_1 = require("./package-metadata-service");
5
+ const release_notes_service_1 = require("./release-notes-service");
6
+ class ChangelogFetcher {
7
+ constructor() {
8
+ this.metadataService = new package_metadata_service_1.PackageMetadataService();
9
+ this.releaseNotesService = new release_notes_service_1.ReleaseNotesService(this.metadataService);
10
+ }
11
+ async fetchPackageMetadata(packageName, version, signal) {
12
+ return await this.metadataService.fetchPackageMetadata(packageName, version, signal);
13
+ }
14
+ getRepositoryReleaseUrl(packageName, version) {
15
+ return this.metadataService.getRepositoryReleaseUrl(packageName, version);
16
+ }
17
+ cacheMetadata(packageName, rawData) {
18
+ this.metadataService.cacheMetadata(packageName, rawData);
19
+ }
20
+ async fetchReleaseNotesForVersion(packageName, version, signal) {
21
+ return await this.releaseNotesService.fetchReleaseNotesForVersion(packageName, version, signal);
22
+ }
23
+ clearCache() {
24
+ this.metadataService.clearCache();
25
+ this.releaseNotesService.clearCache();
26
+ }
27
+ }
28
+ exports.ChangelogFetcher = ChangelogFetcher;
29
+ exports.changelogFetcher = new ChangelogFetcher();
30
+ //# sourceMappingURL=changelog-service.js.map
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PackageMetadataService = void 0;
4
+ const npm_registry_client_1 = require("../clients/npm-registry-client");
5
+ const package_metadata_1 = require("../parsers/package-metadata");
6
+ const jsdelivr_registry_1 = require("../../../services/jsdelivr-registry");
7
+ class PackageMetadataService {
8
+ constructor(npmRegistryClient = new npm_registry_client_1.NpmRegistryClient(), exactManifestFetcher = jsdelivr_registry_1.fetchExactPackageManifest) {
9
+ this.npmRegistryClient = npmRegistryClient;
10
+ this.exactManifestFetcher = exactManifestFetcher;
11
+ this.cache = new Map();
12
+ this.inFlight = new Map();
13
+ }
14
+ clearCache() {
15
+ this.cache.clear();
16
+ this.inFlight.clear();
17
+ }
18
+ getCached(packageName, version) {
19
+ for (const key of [this.getCacheKey(packageName, version), this.getCacheKey(packageName), packageName]) {
20
+ if (this.cache.has(key)) {
21
+ return this.cache.get(key) ?? null;
22
+ }
23
+ }
24
+ return null;
25
+ }
26
+ async fetchPackageMetadata(packageName, version, signal) {
27
+ const cacheKey = this.getCacheKey(packageName, version);
28
+ if (this.cache.has(cacheKey)) {
29
+ return this.cache.get(cacheKey) ?? null;
30
+ }
31
+ const inFlight = this.inFlight.get(cacheKey);
32
+ if (inFlight) {
33
+ return await inFlight;
34
+ }
35
+ const lookupPromise = this.fetchAndCachePackageMetadata(packageName, version, signal).finally(() => {
36
+ this.inFlight.delete(cacheKey);
37
+ });
38
+ this.inFlight.set(cacheKey, lookupPromise);
39
+ return await lookupPromise;
40
+ }
41
+ cacheMetadata(packageName, rawData) {
42
+ const metadata = this.buildMetadata(packageName, rawData);
43
+ this.cache.set(packageName, metadata);
44
+ }
45
+ getRepositoryReleaseUrl(packageName, version) {
46
+ const metadata = this.getCached(packageName, version);
47
+ if (!metadata?.releaseNotes) {
48
+ return null;
49
+ }
50
+ return `${metadata.releaseNotes}/tag/v${version}`;
51
+ }
52
+ getCacheKey(packageName, version) {
53
+ return `${packageName}@${version?.trim() || 'latest'}`;
54
+ }
55
+ cachePackageMetadata(packageName, cacheKey, metadata) {
56
+ this.cache.set(cacheKey, metadata);
57
+ this.cache.set(this.getCacheKey(packageName), metadata);
58
+ this.cache.set(packageName, metadata);
59
+ }
60
+ async fetchAndCachePackageMetadata(packageName, version, signal) {
61
+ const cacheKey = this.getCacheKey(packageName, version);
62
+ try {
63
+ signal?.throwIfAborted();
64
+ const manifest = await this.fetchPackageManifest(packageName, version, signal);
65
+ if (!manifest) {
66
+ this.cache.set(cacheKey, null);
67
+ return null;
68
+ }
69
+ const metadata = (0, package_metadata_1.mapPackageManifestToMetadata)(packageName, manifest);
70
+ try {
71
+ signal?.throwIfAborted();
72
+ const downloadsData = await this.npmRegistryClient.fetchDownloadStats(packageName, signal);
73
+ if (downloadsData) {
74
+ metadata.weeklyDownloads = downloadsData.downloads;
75
+ }
76
+ }
77
+ catch {
78
+ // Optional data should not fail metadata hydration.
79
+ }
80
+ this.cachePackageMetadata(packageName, cacheKey, metadata);
81
+ return metadata;
82
+ }
83
+ catch (error) {
84
+ if (error instanceof DOMException && error.name === 'AbortError') {
85
+ throw error;
86
+ }
87
+ this.cache.set(cacheKey, null);
88
+ return null;
89
+ }
90
+ }
91
+ async fetchPackageManifest(packageName, version, signal) {
92
+ signal?.throwIfAborted();
93
+ const normalizedVersion = version?.trim();
94
+ if (normalizedVersion) {
95
+ const jsdelivrManifest = await this.exactManifestFetcher(packageName, normalizedVersion);
96
+ if (jsdelivrManifest) {
97
+ return jsdelivrManifest;
98
+ }
99
+ }
100
+ signal?.throwIfAborted();
101
+ return await this.npmRegistryClient.fetchPackageManifest(packageName, normalizedVersion || 'latest', signal);
102
+ }
103
+ buildMetadata(packageName, rawData) {
104
+ return (0, package_metadata_1.mapPackageManifestToMetadata)(packageName, rawData);
105
+ }
106
+ }
107
+ exports.PackageMetadataService = PackageMetadataService;
108
+ //# sourceMappingURL=package-metadata-service.js.map
@@ -0,0 +1,180 @@
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.ReleaseNotesService = void 0;
37
+ const semver = __importStar(require("semver"));
38
+ const github_client_1 = require("../clients/github-client");
39
+ const changelog_parser_1 = require("../parsers/changelog-parser");
40
+ const github_release_html_parser_1 = require("../parsers/github-release-html-parser");
41
+ const constants_1 = require("../../../config/constants");
42
+ const RELEASE_NOTES_FETCH_TIMEOUT_MS = 5000;
43
+ const PREFER_GITHUB_RELEASE_PAGE = true;
44
+ class ReleaseNotesService {
45
+ constructor(metadataService, githubClient = new github_client_1.GitHubClient()) {
46
+ this.metadataService = metadataService;
47
+ this.githubClient = githubClient;
48
+ this.releaseNotesCache = new Map();
49
+ this.releaseNotesInFlight = new Map();
50
+ }
51
+ clearCache() {
52
+ this.releaseNotesCache.clear();
53
+ this.releaseNotesInFlight.clear();
54
+ this.githubClient.clearCache();
55
+ }
56
+ async fetchReleaseNotesForVersion(packageName, version, signal) {
57
+ const cacheKey = `release-notes:${packageName}@${version}`;
58
+ if (this.releaseNotesCache.has(cacheKey)) {
59
+ return this.releaseNotesCache.get(cacheKey);
60
+ }
61
+ const inFlight = this.releaseNotesInFlight.get(cacheKey);
62
+ if (inFlight) {
63
+ return await inFlight;
64
+ }
65
+ const promise = this.doFetchReleaseNotes(packageName, version, signal)
66
+ .then((result) => {
67
+ this.releaseNotesCache.set(cacheKey, result);
68
+ return result;
69
+ })
70
+ .finally(() => {
71
+ this.releaseNotesInFlight.delete(cacheKey);
72
+ });
73
+ this.releaseNotesInFlight.set(cacheKey, promise);
74
+ return await promise;
75
+ }
76
+ async doFetchReleaseNotes(packageName, version, callerSignal) {
77
+ const timeoutSignal = AbortSignal.timeout(RELEASE_NOTES_FETCH_TIMEOUT_MS);
78
+ const signal = callerSignal ? AbortSignal.any([callerSignal, timeoutSignal]) : timeoutSignal;
79
+ signal.throwIfAborted();
80
+ const metadata = this.metadataService.getCached(packageName, version) ??
81
+ (await this.metadataService.fetchPackageMetadata(packageName, version, signal));
82
+ const repoUrl = metadata?.repositoryUrl || '';
83
+ if (repoUrl.includes('github.com')) {
84
+ for (const loadSource of this.getGitHubSources(repoUrl, version, signal)) {
85
+ const notes = await loadSource();
86
+ if (notes)
87
+ return notes;
88
+ }
89
+ }
90
+ const changelogNotes = await this.fetchJsdelivrChangelog(packageName, version, signal);
91
+ if (changelogNotes)
92
+ return changelogNotes;
93
+ return null;
94
+ }
95
+ getGitHubSources(repoUrl, version, signal) {
96
+ const directReleaseSources = PREFER_GITHUB_RELEASE_PAGE
97
+ ? [
98
+ () => this.fetchGitHubReleasePageNotes(repoUrl, version, signal),
99
+ () => this.fetchGitHubReleaseNotes(repoUrl, version, signal),
100
+ ]
101
+ : [
102
+ () => this.fetchGitHubReleaseNotes(repoUrl, version, signal),
103
+ () => this.fetchGitHubReleasePageNotes(repoUrl, version, signal),
104
+ ];
105
+ return [
106
+ ...directReleaseSources,
107
+ () => this.fetchGitHubReleaseListNotes(repoUrl, version, signal),
108
+ () => this.fetchGitHubChangelogMd(repoUrl, version, signal),
109
+ ];
110
+ }
111
+ async fetchGitHubReleasePageNotes(repoUrl, version, signal) {
112
+ for (const tag of [`v${version}`, version]) {
113
+ const html = await this.githubClient.fetchReleasePageHtml(repoUrl, tag, signal);
114
+ if (!html)
115
+ continue;
116
+ const extracted = (0, github_release_html_parser_1.extractReleaseNotesFromHtml)(html);
117
+ if (extracted)
118
+ return extracted;
119
+ }
120
+ return null;
121
+ }
122
+ async fetchGitHubReleaseNotes(repoUrl, version, signal) {
123
+ for (const tag of [`v${version}`, version]) {
124
+ const notes = await this.githubClient.fetchReleaseByTag(repoUrl, tag, signal);
125
+ if (notes)
126
+ return notes;
127
+ }
128
+ return null;
129
+ }
130
+ async fetchGitHubReleaseListNotes(repoUrl, version, signal) {
131
+ const releases = await this.githubClient.fetchReleases(repoUrl, signal);
132
+ if (!releases)
133
+ return null;
134
+ const normalizedVersion = semver.clean(version);
135
+ if (!normalizedVersion)
136
+ return null;
137
+ for (const release of releases) {
138
+ if (release.draft)
139
+ continue;
140
+ const releaseVersion = (0, changelog_parser_1.normalizeReleaseTag)(release.tag_name);
141
+ if (releaseVersion !== normalizedVersion)
142
+ continue;
143
+ if (release.body?.trim()) {
144
+ return release.body.trim();
145
+ }
146
+ }
147
+ return null;
148
+ }
149
+ async fetchGitHubChangelogMd(repoUrl, version, signal) {
150
+ const fullText = await this.githubClient.fetchRawChangelog(repoUrl, signal);
151
+ if (!fullText)
152
+ return null;
153
+ return (0, changelog_parser_1.extractVersionSection)(fullText, version);
154
+ }
155
+ async fetchJsdelivrChangelog(packageName, version, signal) {
156
+ const fullText = await this.fetchPublishedPackageChangelog(packageName, version, signal);
157
+ if (!fullText)
158
+ return null;
159
+ return (0, changelog_parser_1.extractVersionSection)(fullText, version);
160
+ }
161
+ async fetchPublishedPackageChangelog(packageName, version, signal) {
162
+ try {
163
+ const response = await fetch(`${constants_1.JSDELIVR_CDN_URL}/${encodeURIComponent(packageName)}@${version}/CHANGELOG.md`, {
164
+ method: 'GET',
165
+ signal,
166
+ });
167
+ if (!response.ok)
168
+ return null;
169
+ return await response.text();
170
+ }
171
+ catch (error) {
172
+ if (error instanceof DOMException && error.name === 'AbortError') {
173
+ throw error;
174
+ }
175
+ return null;
176
+ }
177
+ }
178
+ }
179
+ exports.ReleaseNotesService = ReleaseNotesService;
180
+ //# sourceMappingURL=release-notes-service.js.map
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=changelog.types.js.map