1 | import { Logger } from '@stryker-mutator/api/logging';
|
2 | import { commonTokens, tokens } from '@stryker-mutator/api/plugin';
|
3 | import { errorToString } from '@stryker-mutator/util';
|
4 | import { IRestResponse, RestClient } from 'typed-rest-client/RestClient';
|
5 |
|
6 | import { PackageInfo } from './package-info.js';
|
7 | import { PromptOption } from './prompt-option.js';
|
8 |
|
9 | import { initializerTokens } from './index.js';
|
10 |
|
11 | interface NpmSearchResult {
|
12 | total: number;
|
13 | results: Array<{ package: PackageInfo }>;
|
14 | }
|
15 |
|
16 | export interface NpmPackage {
|
17 | name: string;
|
18 | homepage?: string;
|
19 | initStrykerConfig?: Record<string, unknown>;
|
20 | }
|
21 |
|
22 | const getName = (packageName: string) => {
|
23 | return packageName.replace('@stryker-mutator/', '').replace('stryker-', '').split('-')[0];
|
24 | };
|
25 |
|
26 | const mapSearchResultToPromptOption = (searchResults: NpmSearchResult): PromptOption[] =>
|
27 | searchResults.results.map((result) => ({
|
28 | name: getName(result.package.name),
|
29 | pkg: result.package,
|
30 | }));
|
31 |
|
32 | const handleResult =
|
33 | (from: string) =>
|
34 | <T>(response: IRestResponse<T>): T => {
|
35 | if (response.statusCode === 200 && response.result) {
|
36 | return response.result;
|
37 | } else {
|
38 | throw new Error(`Path ${from} resulted in http status code: ${response.statusCode}.`);
|
39 | }
|
40 | };
|
41 |
|
42 | export class NpmClient {
|
43 | public static inject = tokens(commonTokens.logger, initializerTokens.restClientNpmSearch, initializerTokens.restClientNpm);
|
44 | constructor(private readonly log: Logger, private readonly searchClient: RestClient, private readonly packageClient: RestClient) {}
|
45 |
|
46 | public getTestRunnerOptions(): Promise<PromptOption[]> {
|
47 | return this.search('/v2/search?q=keywords:@stryker-mutator/test-runner-plugin').then(mapSearchResultToPromptOption);
|
48 | }
|
49 |
|
50 | public getTestReporterOptions(): Promise<PromptOption[]> {
|
51 | return this.search('/v2/search?q=keywords:@stryker-mutator/reporter-plugin').then(mapSearchResultToPromptOption);
|
52 | }
|
53 |
|
54 | public getAdditionalConfig(pkgInfo: PackageInfo): Promise<NpmPackage> {
|
55 | const path = `/${pkgInfo.name}@${pkgInfo.version}/package.json`;
|
56 | return this.packageClient
|
57 | .get<NpmPackage>(path)
|
58 | .then(handleResult(path))
|
59 | .catch((err) => {
|
60 | this.log.warn(
|
61 | `Could not fetch additional initialization config for dependency ${pkgInfo.name}. You might need to configure it manually`,
|
62 | err
|
63 | );
|
64 | return { name: pkgInfo.name };
|
65 | });
|
66 | }
|
67 |
|
68 | private search(path: string): Promise<NpmSearchResult> {
|
69 | this.log.debug(`Searching: ${path}`);
|
70 | return this.searchClient
|
71 | .get<NpmSearchResult>(path)
|
72 | .then(handleResult(path))
|
73 | .catch((err) => {
|
74 | this.log.error(`Unable to reach npms.io (for query ${path}). Please check your internet connection.`, errorToString(err));
|
75 | const result: NpmSearchResult = {
|
76 | results: [],
|
77 | total: 0,
|
78 | };
|
79 | return result;
|
80 | });
|
81 | }
|
82 | }
|