diff --git a/lib/config/presets/npm/index.ts b/lib/config/presets/npm/index.ts index 6c9b5cc508d51ae542a900d73d668d7a564d48f0..d78e5dd3b8628f0538a74f9dc9084cd39e5d536e 100644 --- a/lib/config/presets/npm/index.ts +++ b/lib/config/presets/npm/index.ts @@ -31,11 +31,11 @@ export async function getPreset({ ); } const body = (await http.getJson<NpmResponse>(packageUrl)).body; - dep = body.versions[body['dist-tags'].latest]; + dep = body.versions[body['dist-tags']?.latest]; } catch (err) { throw new Error(PRESET_DEP_NOT_FOUND); } - if (!dep['renovate-config']) { + if (!dep?.['renovate-config']) { throw new Error(PRESET_RENOVATE_CONFIG_NOT_FOUND); } const presetConfig = dep['renovate-config'][presetName]; diff --git a/lib/modules/datasource/npm/get.spec.ts b/lib/modules/datasource/npm/get.spec.ts index 1c3dce29bef4ea7c886488f1285c5a64e8735f9a..179a7711b538a95eb345907f7f890a4314eba931 100644 --- a/lib/modules/datasource/npm/get.spec.ts +++ b/lib/modules/datasource/npm/get.spec.ts @@ -286,6 +286,27 @@ describe('modules/datasource/npm/get', () => { `); }); + it('handles missing dist-tags latest', async () => { + setNpmrc('registry=https://test.org\n_authToken=XXX'); + + httpMock + .scope('https://test.org') + .get('/@neutrinojs%2Freact') + .reply(200, { + name: '@neutrinojs/react', + repository: { + type: 'git', + url: 'https://github.com/neutrinojs/neutrino/tree/master/packages/react', + }, + versions: { '1.0.0': {} }, + }); + const registryUrl = resolveRegistryUrl('@neutrinojs/react'); + const dep = await getDependency(http, registryUrl, '@neutrinojs/react'); + + expect(dep.sourceUrl).toBe('https://github.com/neutrinojs/neutrino'); + expect(dep.sourceDirectory).toBe('packages/react'); + }); + it('handles mixed sourceUrls in releases', async () => { setNpmrc('registry=https://test.org\n_authToken=XXX'); diff --git a/lib/modules/datasource/npm/get.ts b/lib/modules/datasource/npm/get.ts index 44d1c7aa93b81c66c6b0b285f3bf7d6f05dd84b7..169b8330cd66cd740f7a9393859d0b6aaf208d49 100644 --- a/lib/modules/datasource/npm/get.ts +++ b/lib/modules/datasource/npm/get.ts @@ -87,9 +87,9 @@ export async function getDependency( return null; } - const latestVersion = res.versions[res['dist-tags'].latest]; - res.repository = res.repository || latestVersion.repository; - res.homepage = res.homepage || latestVersion.homepage; + const latestVersion = res.versions[res['dist-tags']?.latest]; + res.repository = res.repository || latestVersion?.repository; + res.homepage = res.homepage || latestVersion?.homepage; const { sourceUrl, sourceDirectory } = getPackageSource(res.repository); @@ -105,7 +105,7 @@ export async function getDependency( registryUrl, }; - if (latestVersion.deprecated) { + if (latestVersion?.deprecated) { dep.deprecationMessage = `On registry \`${registryUrl}\`, the "latest" version of dependency \`${packageName}\` has the following deprecation notice:\n\n\`${latestVersion.deprecated}\`\n\nMarking the latest version of an npm package as deprecated results in the entire package being considered deprecated, so contact the package author you think this is a mistake.`; dep.deprecationSource = id; } diff --git a/lib/modules/datasource/npm/types.ts b/lib/modules/datasource/npm/types.ts index 10b600a75b0e3924456101f889e2e2e38dc5dd0f..facc963e7ada25130e94d2c96206186a5571af28 100644 --- a/lib/modules/datasource/npm/types.ts +++ b/lib/modules/datasource/npm/types.ts @@ -42,7 +42,7 @@ export interface NpmDependency extends ReleaseResult { homepage: string; sourceUrl: string; versions: Record<string, any>; - 'dist-tags': Record<string, string>; + 'dist-tags'?: Record<string, string>; sourceDirectory?: string; }