release-it 19.0.0-next.2 → 19.0.0-next.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -400,7 +400,7 @@ Are you using release-it at work? Please consider [sponsoring me][14]!
400
400
  [29]: ./docs/git.md
401
401
  [30]: https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases
402
402
  [31]: ./docs/github-releases.md
403
- [32]: https://docs.gitlab.com/ce/user/project/releases/
403
+ [32]: https://docs.gitlab.com/api/releases/
404
404
  [33]: https://gitlab.com/profile/personal_access_tokens
405
405
  [34]: ./docs/environment-variables.md
406
406
  [35]: ./docs/gitlab-releases.md
package/bin/release-it.js CHANGED
@@ -1,38 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import updater from 'update-notifier';
4
- import parseArgs from 'yargs-parser';
5
4
  import release from '../lib/cli.js';
6
5
  import { readJSON } from '../lib/util.js';
6
+ import { parseCliArguments } from '../lib/args.js';
7
7
 
8
8
  const pkg = readJSON(new URL('../package.json', import.meta.url));
9
9
 
10
- const aliases = {
11
- c: 'config',
12
- d: 'dry-run',
13
- h: 'help',
14
- i: 'increment',
15
- v: 'version',
16
- V: 'verbose'
17
- };
18
-
19
- const parseCliArguments = args => {
20
- const options = parseArgs(args, {
21
- boolean: ['dry-run', 'ci'],
22
- alias: aliases,
23
- configuration: {
24
- 'parse-numbers': false,
25
- 'camel-case-expansion': false
26
- }
27
- });
28
- if (options.V) {
29
- options.verbose = typeof options.V === 'boolean' ? options.V : options.V.length;
30
- delete options.V;
31
- }
32
- options.increment = options._[0] || options.i;
33
- return options;
34
- };
35
-
36
10
  const options = parseCliArguments([].slice.call(process.argv, 2));
37
11
 
38
12
  updater({ pkg: pkg }).notify();
package/lib/args.js ADDED
@@ -0,0 +1,64 @@
1
+ import parseArgs from 'yargs-parser';
2
+
3
+ const aliases = {
4
+ c: 'config',
5
+ d: 'dry-run',
6
+ h: 'help',
7
+ i: 'increment',
8
+ v: 'version',
9
+ V: 'verbose'
10
+ };
11
+
12
+ const booleanOptions = [
13
+ 'dry-run',
14
+ 'ci',
15
+ 'git',
16
+ 'npm',
17
+ 'github',
18
+ 'gitlab',
19
+ 'git.addUntrackedFiles',
20
+ 'git.requireCleanWorkingDir',
21
+ 'git.requireUpstream',
22
+ 'git.requireCommits',
23
+ 'git.requireCommitsFail',
24
+ 'git.commit',
25
+ 'git.tag',
26
+ 'git.push',
27
+ 'git.getLatestTagFromAllRefs',
28
+ 'git.skipChecks',
29
+ 'github.release',
30
+ 'github.autoGenerate',
31
+ 'github.preRelease',
32
+ 'github.draft',
33
+ 'github.skipChecks',
34
+ 'github.web',
35
+ 'github.comments.submit',
36
+ 'gitlab.release',
37
+ 'gitlab.autoGenerate',
38
+ 'gitlab.preRelease',
39
+ 'gitlab.draft',
40
+ 'gitlab.useIdsForUrls',
41
+ 'gitlab.useGenericPackageRepositoryForAssets',
42
+ 'gitlab.skipChecks',
43
+ 'npm.publish',
44
+ 'npm.ignoreVersion',
45
+ 'npm.allowSameVersion',
46
+ 'npm.skipChecks'
47
+ ];
48
+
49
+ export const parseCliArguments = args => {
50
+ const options = parseArgs(args, {
51
+ boolean: booleanOptions,
52
+ alias: aliases,
53
+ configuration: {
54
+ 'parse-numbers': false,
55
+ 'camel-case-expansion': false
56
+ }
57
+ });
58
+ if (options.V) {
59
+ options.verbose = typeof options.V === 'boolean' ? options.V : options.V.length;
60
+ delete options.V;
61
+ }
62
+ options.increment = options._[0] || options.i;
63
+ return options;
64
+ };
package/lib/log.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { EOL } from 'node:os';
2
- import chalk from 'chalk';
2
+ import { styleText } from 'node:util';
3
3
  import { isObjectLoose } from '@phun-ky/typeof';
4
4
  import { upperFirst } from './util.js';
5
5
 
@@ -20,15 +20,15 @@ class Logger {
20
20
  }
21
21
 
22
22
  error(...args) {
23
- console.error(chalk.red('ERROR'), ...args);
23
+ console.error([styleText('red', 'ERROR'), ...args].join(' '));
24
24
  }
25
25
 
26
26
  info(...args) {
27
- console.error(chalk.grey(...args));
27
+ console.error(styleText('grey', args.join(' ')));
28
28
  }
29
29
 
30
30
  warn(...args) {
31
- console.error(chalk.yellow('WARNING'), ...args);
31
+ console.error([styleText('yellow', 'WARNING'), ...args].join(' '));
32
32
  }
33
33
 
34
34
  verbose(...args) {
@@ -58,7 +58,7 @@ class Logger {
58
58
 
59
59
  preview({ title, text }) {
60
60
  if (text) {
61
- const header = chalk.bold(upperFirst(title));
61
+ const header = styleText('bold', upperFirst(title));
62
62
  const body = text.replace(new RegExp(EOL + EOL, 'g'), EOL);
63
63
  this.obtrusive(`${header}:${EOL}${body}`);
64
64
  } else {
@@ -131,7 +131,7 @@ class Git extends GitBase {
131
131
  async getCommitsSinceLatestTag(commitsPath = '') {
132
132
  const latestTagName = await this.getLatestTagName();
133
133
  const ref = latestTagName ? `${latestTagName}..HEAD` : 'HEAD';
134
- return this.exec(`git rev-list ${ref} --count ${commitsPath}`, { options }).then(Number);
134
+ return this.exec(`git rev-list ${ref} --count ${commitsPath ? `-- ${commitsPath}` : ''}`, { options }).then(Number);
135
135
  }
136
136
 
137
137
  async getUpstreamArgs(pushRepo) {
@@ -1,5 +1,6 @@
1
1
  import path from 'node:path';
2
- import fs, { promises } from 'node:fs'; // import fs here so it can be stubbed in tests
2
+ import fs from 'node:fs'; // import fs here so it can be stubbed in tests
3
+ import { readFile } from 'node:fs/promises';
3
4
  import { globby } from 'globby';
4
5
  import { Agent } from 'undici';
5
6
  import Release from '../GitRelease.js';
@@ -264,14 +265,17 @@ class GitLab extends Release {
264
265
  const name = path.basename(filePath);
265
266
  const { useIdsForUrls, useGenericPackageRepositoryForAssets, genericPackageRepositoryName } = this.options;
266
267
  const { id, origin, repo, version, baseUrl } = this.getContext();
268
+
267
269
  const endpoint = useGenericPackageRepositoryForAssets
268
270
  ? `projects/${id}/packages/generic/${genericPackageRepositoryName}/${version}/${name}`
269
271
  : `projects/${id}/uploads`;
272
+
270
273
  if (useGenericPackageRepositoryForAssets) {
271
274
  const options = {
272
275
  method: 'PUT',
273
- body: await promises.readFile(filePath)
276
+ body: await readFile(filePath)
274
277
  };
278
+
275
279
  try {
276
280
  const body = await this.request(endpoint, options);
277
281
  if (!(body.message && body.message == '201 Created')) {
@@ -288,7 +292,7 @@ class GitLab extends Release {
288
292
  }
289
293
  } else {
290
294
  const body = new FormData();
291
- const rawData = await promises.readFile(filePath);
295
+ const rawData = await readFile(filePath);
292
296
  body.set('file', new Blob([rawData]), name);
293
297
  const options = { body };
294
298
 
@@ -1,9 +1,7 @@
1
+ import { styleText } from 'node:util';
1
2
  import semver from 'semver';
2
- import chalk from 'chalk';
3
3
  import Plugin from '../Plugin.js';
4
4
 
5
- const { green, red, redBright } = chalk;
6
-
7
5
  const RELEASE_TYPES = ['patch', 'minor', 'major'];
8
6
  const PRERELEASE_TYPES = ['prepatch', 'preminor', 'premajor'];
9
7
  const CONTINUATION_TYPES = ['prerelease', 'pre'];
@@ -30,7 +28,11 @@ const getIncrementChoices = context => {
30
28
  };
31
29
 
32
30
  const versionTransformer = context => input =>
33
- semver.valid(input) ? (semver.gt(input, context.latestVersion) ? green(input) : red(input)) : redBright(input);
31
+ semver.valid(input)
32
+ ? semver.gt(input, context.latestVersion)
33
+ ? styleText('green', input)
34
+ : styleText('red', input)
35
+ : styleText(['red', 'bold'], input);
34
36
 
35
37
  const prompts = {
36
38
  incrementList: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "release-it",
3
- "version": "19.0.0-next.2",
3
+ "version": "19.0.0-next.4",
4
4
  "description": "Generic CLI tool to automate versioning and package publishing-related tasks.",
5
5
  "keywords": [
6
6
  "build",
@@ -81,51 +81,48 @@
81
81
  "@iarna/toml": "2.2.5",
82
82
  "@nodeutils/defaults-deep": "1.1.0",
83
83
  "@octokit/rest": "21.1.1",
84
- "@phun-ky/typeof": "1.2.3",
84
+ "@phun-ky/typeof": "1.2.4",
85
85
  "async-retry": "1.3.3",
86
- "chalk": "5.4.1",
87
86
  "ci-info": "^4.2.0",
88
87
  "cosmiconfig": "9.0.0",
89
88
  "eta": "3.5.0",
90
89
  "execa": "9.5.2",
91
90
  "git-url-parse": "16.0.1",
92
91
  "globby": "14.1.0",
93
- "inquirer": "12.5.0",
92
+ "inquirer": "12.5.2",
94
93
  "issue-parser": "7.0.1",
95
94
  "lodash.get": "4.4.2",
96
95
  "lodash.merge": "4.6.2",
97
- "mime-types": "2.1.35",
96
+ "mime-types": "3.0.1",
98
97
  "new-github-release-url": "2.0.0",
99
98
  "open": "10.1.0",
100
99
  "ora": "8.2.0",
101
100
  "os-name": "6.0.0",
102
101
  "proxy-agent": "6.5.0",
103
102
  "semver": "7.7.1",
104
- "undici": "6.21.1",
103
+ "undici": "6.21.2",
105
104
  "update-notifier": "7.3.1",
106
105
  "url-join": "5.0.0",
107
106
  "wildcard-match": "5.1.4",
108
107
  "yargs-parser": "21.1.1"
109
108
  },
110
109
  "devDependencies": {
111
- "@eslint/compat": "1.2.7",
110
+ "@eslint/compat": "1.2.8",
112
111
  "@eslint/eslintrc": "3.3.1",
113
- "@eslint/js": "9.23.0",
112
+ "@eslint/js": "9.24.0",
114
113
  "@octokit/request-error": "6.1.7",
115
- "@types/node": "20.17.24",
116
- "eslint": "9.23.0",
117
- "eslint-config-prettier": "10.1.1",
118
- "eslint-plugin-import-x": "4.9.3",
119
- "eslint-plugin-prettier": "5.2.5",
114
+ "@types/node": "20.17.28",
115
+ "eslint": "9.24.0",
116
+ "eslint-plugin-import-x": "4.10.2",
120
117
  "globals": "16.0.0",
121
118
  "installed-check": "9.3.0",
122
- "knip": "5.46.1",
119
+ "knip": "5.48.0",
123
120
  "mentoss": "0.9.0",
124
121
  "mock-stdio": "1.0.3",
125
122
  "prettier": "3.5.3",
126
123
  "remark-cli": "12.0.1",
127
124
  "remark-preset-webpro": "1.1.1",
128
- "typescript": "5.8.2"
125
+ "typescript": "5.8.3"
129
126
  },
130
127
  "overrides": {
131
128
  "pac-resolver": "7.0.1",
package/schema/git.json CHANGED
@@ -38,8 +38,8 @@
38
38
  "default": ""
39
39
  },
40
40
  "addUntrackedFiles": {
41
- "type": "string",
42
- "default": ""
41
+ "type": "boolean",
42
+ "default": false
43
43
  },
44
44
  "commit": {
45
45
  "type": "boolean",
@@ -53,6 +53,10 @@
53
53
  },
54
54
  "default": []
55
55
  },
56
+ "commitMessage": {
57
+ "type": "string",
58
+ "default": null
59
+ },
56
60
  "tag": {
57
61
  "type": "boolean",
58
62
  "default": true
package/test/args.js ADDED
@@ -0,0 +1,27 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { parseCliArguments } from '../lib/args.js';
4
+
5
+ test("should parse boolean arguments", () => {
6
+ const args = [
7
+ '--dry-run=false',
8
+ '--ci',
9
+ '--github=false',
10
+ '--no-npm',
11
+ '--git.addUntrackedFiles=true',
12
+ '--git.commit=false',
13
+ '--no-git.tag',
14
+ '--git.commitMessage=test',
15
+ ]
16
+
17
+ const result = parseCliArguments(args);
18
+
19
+ assert.equal(result['dry-run'], false);
20
+ assert.equal(result.ci, true);
21
+ assert.equal(result.github, false);
22
+ assert.equal(result.npm, false);
23
+ assert.equal(result.git.addUntrackedFiles, true);
24
+ assert.equal(result.git.commit, false);
25
+ assert.equal(result.git.tag, false);
26
+ assert.equal(result.git.commitMessage, 'test');
27
+ });
package/test/config.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import test, { describe, before, after, afterEach } from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
  import { isCI } from 'ci-info';
4
- import { MockServer, FetchMocker } from 'mentoss';
5
4
  import Config, { getRemoteConfiguration } from '../lib/config.js';
6
5
  import { readJSON } from '../lib/util.js';
6
+ import { mockFetch } from './util/mock.js';
7
7
 
8
8
  const defaultConfig = readJSON(new URL('../config/release-it.json', import.meta.url));
9
9
  const projectConfig = readJSON(new URL('../.release-it.json', import.meta.url));
@@ -165,11 +165,7 @@ describe('config', () => {
165
165
  });
166
166
 
167
167
  describe('fetch extended configuration', () => {
168
- const server = new MockServer('https://raw.githubusercontent.com');
169
-
170
- const mocker = new FetchMocker({
171
- servers: [server]
172
- });
168
+ const [mocker, server] = mockFetch('https://raw.githubusercontent.com');
173
169
 
174
170
  before(() => {
175
171
  mocker.mockGlobal();
package/test/github.js CHANGED
@@ -1,7 +1,6 @@
1
1
  import test, { describe, before, after, afterEach } from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
  import { RequestError } from '@octokit/request-error';
4
- import { MockServer, FetchMocker } from 'mentoss';
5
4
  import GitHub from '../lib/plugin/github/GitHub.js';
6
5
  import { getSearchQueries } from '../lib/plugin/github/util.js';
7
6
  import { factory, runTasks } from './util/index.js';
@@ -13,6 +12,7 @@ import {
13
12
  interceptUpdate,
14
13
  interceptAsset
15
14
  } from './stub/github.js';
15
+ import { mockFetch } from './util/mock.js';
16
16
 
17
17
  describe('github', () => {
18
18
  const tokenRef = 'GITHUB_TOKEN';
@@ -21,14 +21,12 @@ describe('github', () => {
21
21
  const git = { changelog: '' };
22
22
  const requestErrorOptions = { request: { url: '', headers: {} }, response: { headers: {} } };
23
23
 
24
- const api = new MockServer('https://api.github.com');
25
- const assets = new MockServer('https://uploads.github.com');
26
- const example = new MockServer('https://github.example.org/api/v3');
27
- const custom = new MockServer('https://custom.example.org/api/v3');
28
-
29
- const mocker = new FetchMocker({
30
- servers: [api, assets, example, custom]
31
- });
24
+ const [mocker, api, assets, example, custom] = mockFetch([
25
+ 'https://api.github.com',
26
+ 'https://uploads.github.com',
27
+ 'https://github.example.org/api/v3',
28
+ 'https://custom.example.org/api/v3'
29
+ ]);
32
30
 
33
31
  before(() => {
34
32
  mocker.mockGlobal();
package/test/gitlab.js CHANGED
@@ -2,7 +2,6 @@ import fs from 'node:fs';
2
2
  import test, { before, after, afterEach, beforeEach, describe } from 'node:test';
3
3
  import assert from 'node:assert/strict';
4
4
  import { Agent } from 'undici';
5
- import { MockServer, FetchMocker } from 'mentoss';
6
5
  import Git from '../lib/plugin/git/Git.js';
7
6
  import GitLab from '../lib/plugin/gitlab/GitLab.js';
8
7
  import { GitlabTestServer } from './util/https-server/server.js';
@@ -13,21 +12,21 @@ import {
13
12
  interceptPublish,
14
13
  interceptAsset,
15
14
  interceptAssetGeneric,
16
- interceptMilestones
15
+ interceptMilestones,
16
+ interceptMembers
17
17
  } from './stub/gitlab.js';
18
+ import { mockFetch } from './util/mock.js';
18
19
 
19
20
  describe('GitLab', () => {
20
21
  const tokenHeader = 'Private-Token';
21
22
  const tokenRef = 'GITLAB_TOKEN';
22
23
  const certificateAuthorityFileRef = 'CI_SERVER_TLS_CA_FILE';
23
24
 
24
- const api = new MockServer('https://gitlab.com/api/v4');
25
- const example = new MockServer('https://gitlab.example.org/api/v4');
26
- const local = new MockServer('https://localhost:3000/api/v4');
27
-
28
- const mocker = new FetchMocker({
29
- servers: [api, example, local]
30
- });
25
+ const [mocker, api, example, local] = mockFetch([
26
+ 'https://gitlab.com/api/v4',
27
+ 'https://gitlab.example.org/api/v4',
28
+ 'https://localhost:3000/api/v4'
29
+ ]);
31
30
 
32
31
  before(() => {
33
32
  mocker.mockGlobal();
@@ -129,7 +128,7 @@ describe('GitLab', () => {
129
128
  assert.equal(releaseUrl, `${pushRepo}/-/releases/2.0.1`);
130
129
  });
131
130
 
132
- test('should upload assets with ID-based URLs too', async t => {
131
+ test('should upload assets with ID-based URLs', async t => {
133
132
  const host = 'https://gitlab.com';
134
133
  const pushRepo = `${host}/user/repo`;
135
134
  const options = {
@@ -266,7 +265,7 @@ describe('GitLab', () => {
266
265
  const options = { gitlab: { tokenRef, pushRepo, host } };
267
266
  const gitlab = factory(GitLab, { options });
268
267
 
269
- api.get(`/projects/john%2Frepo/members/all/1`, { status: 200, username: 'emma' });
268
+ interceptMembers(api, { owner: 'emma' });
270
269
  interceptUser(api, { owner: 'john' });
271
270
 
272
271
  await assert.rejects(runTasks(gitlab), /User john is not a collaborator for john\/repo/);
@@ -278,7 +277,7 @@ describe('GitLab', () => {
278
277
  const options = { gitlab: { tokenRef, pushRepo, host } };
279
278
  const gitlab = factory(GitLab, { options });
280
279
 
281
- api.get(`/projects/john%2Frepo/members/all/1`, { status: 200, username: 'john', access_level: 10 });
280
+ interceptMembers(api, { owner: 'john', access_level: 10 });
282
281
  interceptUser(api, { owner: 'john' });
283
282
 
284
283
  await assert.rejects(runTasks(gitlab), /User john is not a collaborator for john\/repo/);
@@ -1,3 +1,7 @@
1
+ export const interceptMembers = (server, { owner = 'emma' } = {}) => {
2
+ server.get(`/projects/john%2Frepo/members/all/1`, { status: 200, username: owner });
3
+ };
4
+
1
5
  export const interceptUser = (server, { owner = 'user' } = {}, options = {}) => {
2
6
  server.get({ url: '/user', ...options }, { status: 200, body: { id: 1, username: owner } });
3
7
  };
@@ -52,10 +56,8 @@ export const interceptAsset = (server, { owner = 'user', project = 'repo' } = {}
52
56
  url: `/projects/${owner}%2F${project}/uploads`
53
57
  },
54
58
  async request => {
55
- const reader = request.body.getReader();
56
- const { value } = await reader.read();
57
- const bodyText = new TextDecoder().decode(value);
58
- const [, name] = bodyText.match(/filename="([^"]+)"/);
59
+ const formData = await request.formData();
60
+ const { name } = formData.get('file');
59
61
  return {
60
62
  status: 200,
61
63
  body: {
@@ -3,7 +3,6 @@ import { renameSync } from 'node:fs';
3
3
  import childProcess from 'node:child_process';
4
4
  import test, { afterEach, after, before, beforeEach, describe, mock } from 'node:test';
5
5
  import assert from 'node:assert/strict';
6
- import { MockServer, FetchMocker } from 'mentoss';
7
6
  import Prompt from '../lib/prompt.js';
8
7
  import Config from '../lib/config.js';
9
8
  import runTasks from '../lib/index.js';
@@ -14,15 +13,14 @@ import ShellStub from './stub/shell.js';
14
13
  import { interceptPublish as interceptGitLabPublish } from './stub/gitlab.js';
15
14
  import { interceptCreate as interceptGitHubCreate } from './stub/github.js';
16
15
  import { factory, LogStub, SpinnerStub } from './util/index.js';
16
+ import { mockFetch } from './util/mock.js';
17
17
 
18
18
  describe('tasks.interactive', () => {
19
- const github = new MockServer('https://api.github.com');
20
- const gitlab = new MockServer('https://gitlab.com/api/v4');
21
- const githubusercontent = new MockServer('https://raw.githubusercontent.com');
22
-
23
- const mocker = new FetchMocker({
24
- servers: [github, gitlab, githubusercontent]
25
- });
19
+ const [mocker, github, gitlab, githubusercontent] = mockFetch([
20
+ 'https://api.github.com',
21
+ 'https://gitlab.com/api/v4',
22
+ 'https://raw.githubusercontent.com'
23
+ ]);
26
24
 
27
25
  before(() => {
28
26
  mocker.mockGlobal();
package/test/tasks.js CHANGED
@@ -4,7 +4,6 @@ import { appendFileSync, mkdirSync, renameSync } from 'node:fs';
4
4
  import test, { after, afterEach, before, beforeEach, describe } from 'node:test';
5
5
  import assert from 'node:assert/strict';
6
6
  import semver from 'semver';
7
- import { MockServer, FetchMocker } from 'mentoss';
8
7
  import Config from '../lib/config.js';
9
8
  import runTasks from '../lib/index.js';
10
9
  import Git from '../lib/plugin/git/Git.js';
@@ -24,17 +23,16 @@ import {
24
23
  interceptAsset as interceptGitHubAsset
25
24
  } from './stub/github.js';
26
25
  import { factory, LogStub, SpinnerStub } from './util/index.js';
26
+ import { mockFetch } from './util/mock.js';
27
27
 
28
28
  describe('tasks', () => {
29
29
  const rootDir = new URL('..', import.meta.url);
30
30
 
31
- const github = new MockServer('https://api.github.com');
32
- const assets = new MockServer('https://uploads.github.com');
33
- const gitlab = new MockServer('https://gitlab.com/api/v4');
34
-
35
- const mocker = new FetchMocker({
36
- servers: [github, assets, gitlab]
37
- });
31
+ const [mocker, github, assets, gitlab] = mockFetch([
32
+ 'https://api.github.com',
33
+ 'https://uploads.github.com',
34
+ 'https://gitlab.com/api/v4'
35
+ ]);
38
36
 
39
37
  const npmMajorVersion = semver.major(process.env.npm_config_user_agent.match(/npm\/([^ ]+)/)[1]);
40
38
 
@@ -0,0 +1,11 @@
1
+ import { MockServer, FetchMocker } from 'mentoss';
2
+
3
+ export const mockFetch = baseUrls => {
4
+ const servers = [baseUrls].flat().map(url => new MockServer(url));
5
+
6
+ const mocker = new FetchMocker({
7
+ servers
8
+ });
9
+
10
+ return [mocker, ...servers];
11
+ };