1 | 1 | | import semver from 'semver'; |
2 | 2 | | import memoize from 'lodash.memoize'; |
3 | 3 | | import { createSelector } from '@reduxjs/toolkit'; |
4 | | - | import { GithubAdvisorySeverity } from '@gradejs-public/shared'; |
| 4 | + | //import { GithubAdvisorySeverity } from '@gradejs-public/shared'; |
5 | 5 | | import { RootState } from '../'; |
6 | | - | import { FiltersState } from '../../components/layouts/Filters/Filters'; |
7 | | - | import { SeverityWeightMap } from '../../components/ui/Vulnerability/Vulnerability'; |
8 | | - | import type { ClientApi } from '../../services/apiClient'; |
| 6 | + | //import { FiltersState } from '../../components/layouts/Filters/Filters'; |
| 7 | + | //import { SeverityWeightMap } from '../../components/ui/Vulnerability/Vulnerability'; |
| 8 | + | import type { ClientApi, GetWebPageScanOutput } from '../../services/apiClient'; |
| 9 | + | |
| 10 | + | export type IdentifiedPackage = ClientApi.ScanResultPackageResponse & { |
| 11 | + | approximateByteSize?: number; |
| 12 | + | outdated?: boolean; |
| 13 | + | vulnerable?: boolean; |
| 14 | + | duplicate?: boolean; |
| 15 | + | }; |
9 | 16 | | |
10 | 17 | | const getFlags = (state: RootState) => ({ |
11 | 18 | | isLoading: state.webpageResults.isLoading, |
12 | 19 | | isFailed: state.webpageResults.isFailed, |
13 | 20 | | }); |
| 21 | + | |
14 | 22 | | const getScanStatus = (state: RootState) => state.webpageResults.detectionResult?.status; |
| 23 | + | export type ScanStatus = ReturnType<typeof getScanStatus>; |
| 24 | + | |
| 25 | + | const getPackagesMemoized = memoize((result: GetWebPageScanOutput['scanResult']) => { |
| 26 | + | const packages: IdentifiedPackage[] = result?.identifiedPackages ?? []; |
| 27 | + | |
| 28 | + | for (const pkg of packages) { |
| 29 | + | pkg.approximateByteSize = pkg.moduleIds.reduce((acc: number, id) => { |
| 30 | + | const size: number = result?.identifiedModuleMap?.[id]?.approximateByteSize ?? 0; |
| 31 | + | return acc + size; |
| 32 | + | }, 0); |
| 33 | + | pkg.duplicate = false; // TODO |
| 34 | + | pkg.outdated = !!( |
| 35 | + | pkg.registryMetadata && |
| 36 | + | !pkg.versionSet.some( |
| 37 | + | (ver) => pkg.registryMetadata && semver.eq(pkg.registryMetadata.latestVersion, ver) |
| 38 | + | ) |
| 39 | + | ); |
| 40 | + | pkg.vulnerable = (result?.vulnerabilities[pkg.name]?.length ?? 0) > 0; |
| 41 | + | } |
| 42 | + | return packages; |
| 43 | + | }); |
| 44 | + | |
15 | 45 | | const getPackages = (state: RootState) => |
16 | | - | state.webpageResults.detectionResult?.scanResult?.packages; |
| 46 | + | getPackagesMemoized(state.webpageResults.detectionResult?.scanResult); |
| 47 | + | |
17 | 48 | | const getVulnerabilities = (state: RootState) => |
18 | 49 | | state.webpageResults.detectionResult?.scanResult?.vulnerabilities; |
| 50 | + | |
19 | 51 | | const getSorting = (state: RootState) => state.webpageResults.filters.sort; |
| 52 | + | |
20 | 53 | | const getFilter = (state: RootState) => state.webpageResults.filters.filter; |
21 | | - | const getPackageNameFilter = (state: RootState) => state.webpageResults.filters.filterPackageName; |
22 | 54 | | |
23 | | - | const compareByPopularity = ( |
24 | | - | left: ClientApi.ScanResultPackageResponse, |
25 | | - | right: ClientApi.ScanResultPackageResponse |
26 | | - | ) => |
| 55 | + | const getKeywords = (state: RootState) => [ |
| 56 | + | ...new Set( |
| 57 | + | state.webpageResults.detectionResult?.scanResult?.identifiedPackages.reduce((acc, pkg) => { |
| 58 | + | return acc.concat(pkg.registryMetadata?.keywords ?? []); |
| 59 | + | }, [] as string[]) |
| 60 | + | ), |
| 61 | + | ]; |
| 62 | + | |
| 63 | + | /* |
| 64 | + | const compareByPopularity = (left: IdentifiedPackage, right: IdentifiedPackage) => |
27 | 65 | | (right.registryMetadata?.monthlyDownloads ?? 0) - (left.registryMetadata?.monthlyDownloads ?? 0); |
28 | 66 | | |
29 | 67 | | const pickHighestSeverity = memoize( |
| skipped 13 lines |
43 | 81 | | const sortingModes: Record< |
44 | 82 | | FiltersState['sort'], |
45 | 83 | | ( |
46 | | - | packages: ClientApi.ScanResultPackageResponse[], |
| 84 | + | packages: IdentifiedPackage[], |
47 | 85 | | vulnerabilities: Record<string, ClientApi.PackageVulnerabilityResponse[]> |
48 | 86 | | ) => ClientApi.ScanResultPackageResponse[] |
49 | 87 | | > = { |
| skipped 22 lines |
72 | 110 | | |
73 | 111 | | const filterModes: Record< |
74 | 112 | | FiltersState['filter'], |
75 | | - | ( |
76 | | - | packages: ClientApi.ScanResultPackageResponse[], |
77 | | - | vulnerabilities: Record<string, ClientApi.PackageVulnerabilityResponse[]>, |
78 | | - | packageName?: string |
79 | | - | ) => ClientApi.ScanResultPackageResponse[] |
| 113 | + | (packages: IdentifiedPackage[], packageName?: string) => IdentifiedPackage[] |
80 | 114 | | > = { |
81 | | - | name: (packages, vulnerabilities, packageName) => { |
82 | | - | if (!packageName) { |
83 | | - | return packages; |
84 | | - | } |
85 | | - | return packages.filter((pkg) => pkg.name.includes(packageName)); |
86 | | - | }, |
87 | | - | outdated: (packages) => |
88 | | - | packages.filter( |
89 | | - | (pkg) => |
90 | | - | pkg.registryMetadata && semver.gtr(pkg.registryMetadata.latestVersion, pkg.versionRange) |
91 | | - | ), |
92 | | - | vulnerable: (packages, vulnerabilities) => packages.filter((pkg) => !!vulnerabilities[pkg.name]), |
| 115 | + | outdated: (packages) => packages.filter((pkg) => !!pkg.outdated), |
| 116 | + | vulnerable: (packages) => packages.filter((pkg) => !!pkg.vulnerable), |
93 | 117 | | all: (packages) => packages, |
94 | | - | }; |
| 118 | + | };*/ |
95 | 119 | | |
96 | 120 | | export const selectors = { |
97 | | - | default: createSelector([getScanStatus, getVulnerabilities], (scanStatus, vulnerabilities) => ({ |
98 | | - | status: scanStatus, |
99 | | - | vulnerabilities, |
100 | | - | })), |
| 121 | + | default: createSelector( |
| 122 | + | [getScanStatus, getVulnerabilities, getKeywords], |
| 123 | + | (status, vulnerabilities, keywordsList) => ({ |
| 124 | + | status, |
| 125 | + | vulnerabilities, |
| 126 | + | keywordsList, |
| 127 | + | }) |
| 128 | + | ), |
101 | 129 | | stateFlags: createSelector( |
102 | 130 | | [getScanStatus, getPackages, getFlags], |
103 | 131 | | (scanStatus, packages, flags) => ({ |
| skipped 3 lines |
107 | 135 | | isProtected: scanStatus === 'protected', |
108 | 136 | | }) |
109 | 137 | | ), |
110 | | - | packagesStats: createSelector( |
111 | | - | [getPackages, getVulnerabilities], |
112 | | - | (packages = [], vulnerabilities = {}) => ({ |
113 | | - | total: packages.length, |
114 | | - | vulnerable: packages.filter((pkg) => (vulnerabilities[pkg.name]?.length ?? 0) > 0).length, |
115 | | - | outdated: packages.filter( |
116 | | - | (pkg) => |
117 | | - | pkg.registryMetadata && semver.gtr(pkg.registryMetadata.latestVersion, pkg.versionRange) |
118 | | - | ).length, |
119 | | - | }) |
120 | | - | ), |
| 138 | + | packagesStats: createSelector([getPackages], (packages = []) => ({ |
| 139 | + | total: packages.length, |
| 140 | + | vulnerable: packages.filter((pkg) => !!pkg.vulnerable).length, |
| 141 | + | outdated: packages.filter((pkg) => !!pkg.outdated).length, |
| 142 | + | })), |
121 | 143 | | packagesSortedAndFiltered: createSelector( |
122 | | - | [getPackages, getVulnerabilities, getSorting, getFilter, getPackageNameFilter], |
123 | | - | (packages, vulnerabilities, sorting, filter, packageNameFilter) => |
124 | | - | packages && |
| 144 | + | [getPackages, getVulnerabilities, getSorting, getFilter], |
| 145 | + | (packages /*, vulnerabilities, sorting, filter*/) => packages /* && |
125 | 146 | | vulnerabilities && |
126 | | - | filterModes[filter]( |
127 | | - | sortingModes[sorting](packages, vulnerabilities), |
128 | | - | vulnerabilities, |
129 | | - | packageNameFilter |
130 | | - | ) |
| 147 | + | filterModes[filter](sortingModes[sorting](packages, vulnerabilities))*/ |
131 | 148 | | ), |
132 | 149 | | }; |
133 | 150 | | |