Skip to content

Commit 31ac4b6

Browse files
nitodeco9romise
andauthored
feat: show warning for dist tags (#38)
* feat: show warning for dist tags * refactor: simplify and improve dist tag fallback check * chore: revert vite tsconfig path config * fix: prevent dist false positives with v-prefix * refactor: only warn for actual dist tags in metadata * ci: fix * chore: cleanup * chore: update playground --------- Co-authored-by: Vida Xie <vida_2020@163.com>
1 parent 3d57be5 commit 31ac4b6

6 files changed

Lines changed: 69 additions & 1 deletion

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
| `npmx.diagnostics.deprecation` | Show warnings for deprecated packages | `boolean` | `true` |
4646
| `npmx.diagnostics.replacement` | Show suggestions for package replacements | `boolean` | `true` |
4747
| `npmx.diagnostics.vulnerability` | Show warnings for packages with known vulnerabilities | `boolean` | `true` |
48+
| `npmx.diagnostics.distTag` | Show warnings when a dependency uses a dist tag | `boolean` | `true` |
4849

4950
<!-- configs -->
5051

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@
8888
"type": "boolean",
8989
"default": true,
9090
"description": "Show warnings for packages with known vulnerabilities"
91+
},
92+
"npmx.diagnostics.distTag": {
93+
"type": "boolean",
94+
"default": true,
95+
"description": "Show warnings when a dependency uses a dist tag"
9196
}
9297
}
9398
},

playground/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"nuxt": "npm:4.3.0"
66
},
77
"devDependencies": {
8-
"array-includes": "",
8+
"array-includes": "latest",
99
"axios": "",
1010
"is-number": "",
1111
"lodash": "catalog:"

src/providers/diagnostics/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { computed, useActiveTextEditor, useDisposable, useDocumentText, watch }
1010
import { languages } from 'vscode'
1111
import { displayName } from '../../generated-meta'
1212
import { checkDeprecation } from './rules/deprecation'
13+
import { checkDistTag } from './rules/dist-tag'
1314
import { checkReplacement } from './rules/replacement'
1415
import { checkUpgrade } from './rules/upgrade'
1516
import { checkVulnerability } from './rules/vulnerability'
@@ -32,6 +33,8 @@ export function useDiagnostics() {
3233
rules.push(checkUpgrade)
3334
if (config.diagnostics.deprecation)
3435
rules.push(checkDeprecation)
36+
if (config.diagnostics.distTag)
37+
rules.push(checkDistTag)
3538
if (config.diagnostics.replacement)
3639
rules.push(checkReplacement)
3740
if (config.diagnostics.vulnerability)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import type { DiagnosticRule } from '..'
2+
import { npmxPackageUrl } from '#utils/links'
3+
import { isSupportedProtocol, parseVersion } from '#utils/version'
4+
import { DiagnosticSeverity, Uri } from 'vscode'
5+
6+
export const checkDistTag: DiagnosticRule = (dep, pkg) => {
7+
const parsed = parseVersion(dep.version)
8+
if (!parsed || !isSupportedProtocol(parsed.protocol))
9+
return
10+
11+
const tag = parsed.semver
12+
if (!(tag in pkg.distTags))
13+
return
14+
15+
return {
16+
node: dep.versionNode,
17+
message: `"${dep.name}" uses the "${tag}" version tag. This may lead to unexpected breaking changes. Consider pinning to a specific version.`,
18+
severity: DiagnosticSeverity.Warning,
19+
code: {
20+
value: 'dist-tag',
21+
target: Uri.parse(npmxPackageUrl(dep.name)),
22+
},
23+
}
24+
}

tests/diagnostics/dist-tag.test.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import type { DependencyInfo } from '#types/extractor'
2+
import type { PackageInfo } from '#utils/api/package'
3+
import { describe, expect, it } from 'vitest'
4+
import { checkDistTag } from '../../src/providers/diagnostics/rules/dist-tag'
5+
6+
function createDependency(name: string, version: string): DependencyInfo {
7+
return {
8+
name,
9+
version,
10+
nameNode: {},
11+
versionNode: {},
12+
}
13+
}
14+
15+
function createPackageInfo(distTags: Record<string, string>): PackageInfo {
16+
return { distTags } as PackageInfo
17+
}
18+
19+
describe('checkDistTag', () => {
20+
const packageInfo = createPackageInfo({ latest: '2.0.0' })
21+
22+
it('should flag when version matches a dist tag in metadata', async () => {
23+
const dependency = createDependency('lodash', 'latest')
24+
const result = await checkDistTag(dependency, packageInfo)
25+
26+
expect(result).toBeDefined()
27+
})
28+
29+
it('should not flag when version does not match any dist tag in metadata', async () => {
30+
const dependency = createDependency('lodash', 'next')
31+
const result = await checkDistTag(dependency, packageInfo)
32+
33+
expect(result).toBeUndefined()
34+
})
35+
})

0 commit comments

Comments
 (0)