forked from
npmx.dev/npmx.dev
[READ-ONLY]
a fast, modern browser for the npm registry
1/**
2 * Comparison feature types
3 */
4
5/** Available comparison facets */
6export type ComparisonFacet =
7 | 'downloads'
8 | 'packageSize'
9 | 'installSize'
10 | 'moduleFormat'
11 | 'types'
12 | 'engines'
13 | 'vulnerabilities'
14 | 'lastUpdated'
15 | 'license'
16 | 'dependencies'
17 | 'totalDependencies'
18 | 'deprecated'
19 | 'totalLikes'
20
21/** Facet metadata for UI display */
22export interface FacetInfo {
23 id: ComparisonFacet
24 category: 'performance' | 'health' | 'compatibility' | 'security'
25 comingSoon?: boolean
26}
27
28/** Category display order */
29export const CATEGORY_ORDER = ['performance', 'health', 'compatibility', 'security'] as const
30
31/** All available facets with their metadata (ordered by category, then display order within category) */
32export const FACET_INFO: Record<ComparisonFacet, Omit<FacetInfo, 'id'>> = {
33 // Performance
34 packageSize: {
35 category: 'performance',
36 },
37 installSize: {
38 category: 'performance',
39 },
40 dependencies: {
41 category: 'performance',
42 },
43 totalDependencies: {
44 category: 'performance',
45 },
46 // Health
47 downloads: {
48 category: 'health',
49 },
50 totalLikes: {
51 category: 'health',
52 },
53 lastUpdated: {
54 category: 'health',
55 },
56 deprecated: {
57 category: 'health',
58 },
59 // Compatibility
60 engines: {
61 category: 'compatibility',
62 },
63 types: {
64 category: 'compatibility',
65 },
66 moduleFormat: {
67 category: 'compatibility',
68 },
69 // Security
70 license: {
71 category: 'security',
72 },
73 vulnerabilities: {
74 category: 'security',
75 },
76}
77
78/** All facets in display order */
79export const ALL_FACETS: ComparisonFacet[] = Object.keys(FACET_INFO) as ComparisonFacet[]
80
81/** Facets grouped by category (derived from FACET_INFO) */
82export const FACETS_BY_CATEGORY: Record<FacetInfo['category'], ComparisonFacet[]> =
83 ALL_FACETS.reduce(
84 (acc, facet) => {
85 acc[FACET_INFO[facet].category].push(facet)
86 return acc
87 },
88 { performance: [], health: [], compatibility: [], security: [] } as Record<
89 FacetInfo['category'],
90 ComparisonFacet[]
91 >,
92 )
93
94/** Default facets - all non-comingSoon facets */
95export const DEFAULT_FACETS: ComparisonFacet[] = ALL_FACETS.filter(f => !FACET_INFO[f].comingSoon)
96
97/** Facet value that can be compared */
98export interface FacetValue<T = unknown> {
99 /** Raw value for comparison logic */
100 raw: T
101 /** Formatted display string (or ISO date string if type is 'date') */
102 display: string
103 /** Optional status indicator */
104 status?: 'good' | 'info' | 'warning' | 'bad' | 'neutral' | 'muted'
105 /** Value type for special rendering (e.g., dates use DateTime component) */
106 type?: 'date'
107 /** Optional tooltip text to explain the value */
108 tooltip?: string
109}
110
111/** Package data for comparison */
112export interface ComparisonPackage {
113 name: string
114 version: string
115 description?: string
116}
117
118// ComingSoon tests run only when FACET_INFO has at least one comingSoon facet
119export const comingSoonFacets = (Object.keys(FACET_INFO) as ComparisonFacet[]).filter(
120 f => FACET_INFO[f].comingSoon,
121)
122export const hasComingSoonFacets = comingSoonFacets.length > 0