release-it 19.0.0-next.1 → 19.0.0-next.3

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/test/shell.js CHANGED
@@ -1,73 +1,76 @@
1
1
  import childProcess from 'node:child_process';
2
- import test from 'ava';
3
- import sinon from 'sinon';
2
+ import test, { describe } from 'node:test';
3
+ import assert from 'node:assert/strict';
4
4
  import Shell from '../lib/shell.js';
5
- import Log from '../lib/log.js';
6
5
  import { factory } from './util/index.js';
7
6
 
8
- const cwd = childProcess.execSync('pwd', { encoding: 'utf8' }).trim();
7
+ describe('shell', () => {
8
+ const cwd = childProcess.execSync('pwd', { encoding: 'utf8' }).trim();
9
9
 
10
- const shell = factory(Shell);
10
+ const shell = factory(Shell);
11
11
 
12
- test('exec', async t => {
13
- t.is(await shell.exec('echo bar'), 'bar');
14
- });
12
+ test('exec', async () => {
13
+ assert.equal(await shell.exec('echo bar'), 'bar');
14
+ });
15
15
 
16
- test('exec (with context)', async t => {
17
- const exec = cmd => shell.exec(cmd, { verbose: false }, shell.config.getContext());
18
- t.is(await exec(''), undefined);
19
- t.is(await exec('pwd'), cwd);
20
- t.is(await exec('echo ${git.pushArgs}'), '--follow-tags');
21
- t.is(await exec('echo -*- ${github.tokenRef} -*-'), '-*- GITHUB_TOKEN -*-');
22
- });
16
+ test('exec (with context)', async () => {
17
+ const exec = cmd => shell.exec(cmd, { verbose: false }, shell.config.getContext());
18
+ assert.equal(await exec(''), undefined);
19
+ assert.equal(await exec('pwd'), cwd);
20
+ assert.equal(await exec('echo ${git.pushArgs}'), '--follow-tags');
21
+ assert.equal(await exec('echo -*- ${github.tokenRef} -*-'), '-*- GITHUB_TOKEN -*-');
22
+ });
23
23
 
24
- test('exec (with args)', async t => {
25
- t.is(await shell.exec([]), undefined);
26
- t.is(await shell.exec(['pwd']), cwd);
27
- t.is(await shell.exec(['echo', 'a', 'b']), 'a b');
28
- t.is(await shell.exec(['echo', '"a"']), '"a"');
29
- });
24
+ test('exec (with args)', async () => {
25
+ assert.equal(await shell.exec([]), undefined);
26
+ assert.equal(await shell.exec(['pwd']), cwd);
27
+ assert.equal(await shell.exec(['echo', 'a', 'b']), 'a b');
28
+ assert.equal(await shell.exec(['echo', '"a"']), '"a"');
29
+ });
30
30
 
31
- test('exec (dry-run/read-only)', async t => {
32
- const shell = factory(Shell, { options: { 'dry-run': true } });
33
- {
34
- const actual = await shell.exec('pwd', { write: false });
35
- t.is(actual, cwd);
36
- t.is(shell.log.exec.callCount, 1);
37
- t.is(shell.log.exec.firstCall.args[0], 'pwd');
38
- }
39
- {
40
- const actual = await shell.exec('pwd');
41
- t.is(actual, undefined);
42
- t.is(shell.log.exec.callCount, 2);
43
- t.is(shell.log.exec.secondCall.args[0], 'pwd');
44
- t.deepEqual(shell.log.exec.secondCall.lastArg, { isDryRun: true });
45
- }
46
- });
31
+ test('exec (dry-run/read-only)', async () => {
32
+ const shell = factory(Shell, { options: { 'dry-run': true } });
33
+ {
34
+ const actual = await shell.exec('pwd', { write: false });
35
+ assert.equal(actual, cwd);
36
+ assert.equal(shell.log.exec.mock.callCount(), 1);
37
+ assert.equal(shell.log.exec.mock.calls[0].arguments[0], 'pwd');
38
+ }
39
+ {
40
+ const actual = await shell.exec('pwd');
41
+ assert.equal(actual, undefined);
42
+ assert.equal(shell.log.exec.mock.callCount(), 2);
43
+ assert.equal(shell.log.exec.mock.calls[1].arguments[0], 'pwd');
44
+ assert.deepEqual(shell.log.exec.mock.calls[1].arguments.at(-1), { isDryRun: true });
45
+ }
46
+ });
47
47
 
48
- test('exec (verbose)', async t => {
49
- const shell = factory(Shell, { options: { verbose: true } });
50
- const actual = await shell.exec('echo foo');
51
- t.is(shell.log.exec.firstCall.args[0], 'echo foo');
52
- t.is(shell.log.exec.callCount, 1);
53
- t.is(shell.log.verbose.firstCall.args[0], 'foo');
54
- t.is(shell.log.verbose.callCount, 1);
55
- t.is(actual, 'foo');
56
- });
48
+ test('exec (verbose)', async () => {
49
+ const shell = factory(Shell, { options: { verbose: true } });
50
+ const actual = await shell.exec('echo foo');
51
+ assert.equal(shell.log.exec.mock.calls[0].arguments[0], 'echo foo');
52
+ assert.equal(shell.log.exec.mock.callCount(), 1);
53
+ assert.equal(shell.log.verbose.mock.calls[0].arguments[0], 'foo');
54
+ assert.equal(shell.log.verbose.mock.callCount(), 1);
55
+ assert.equal(actual, 'foo');
56
+ });
57
57
 
58
- test('should cache results of command execution', async t => {
59
- const log = sinon.createStubInstance(Log);
60
- const shell = factory(Shell, { container: { log } });
61
- const result1 = await shell.exec('echo foo');
62
- const result2 = await shell.exec('echo foo');
63
- t.is(result1, result2);
64
- t.deepEqual(log.exec.args, [
65
- ['echo foo', { isExternal: false, isCached: false }],
66
- ['echo foo', { isExternal: false, isCached: true }]
67
- ]);
68
- });
58
+ test('should cache results of command execution', async () => {
59
+ const shell = factory(Shell);
60
+ const result1 = await shell.exec('echo foo');
61
+ const result2 = await shell.exec('echo foo');
62
+ assert(result1 === result2);
63
+ assert.deepEqual(
64
+ shell.log.exec.mock.calls.map(call => call.arguments),
65
+ [
66
+ ['echo foo', { isExternal: false, isCached: false }],
67
+ ['echo foo', { isExternal: false, isCached: true }]
68
+ ]
69
+ );
70
+ });
69
71
 
70
- test('should bail out on failed command execution', async t => {
71
- const shell = new Shell({ container: { log: sinon.createStubInstance(Log) } });
72
- await t.throwsAsync(shell.exec('foo'));
72
+ test('should bail out on failed command execution', async () => {
73
+ const shell = new Shell({ container: {} });
74
+ await assert.rejects(shell.exec('foo'));
75
+ });
73
76
  });
package/test/spinner.js CHANGED
@@ -1,12 +1,8 @@
1
- import test from 'ava';
2
- import sinon from 'sinon';
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
3
  import Spinner from '../lib/spinner.js';
4
4
  import Config from '../lib/config.js';
5
5
 
6
- test.beforeEach(t => {
7
- t.context.ora = sinon.spy();
8
- });
9
-
10
6
  const getConfig = options => {
11
7
  const testConfig = {
12
8
  ci: false,
@@ -16,43 +12,43 @@ const getConfig = options => {
16
12
  };
17
13
 
18
14
  test('should not show spinner and not execute task if disabled', async t => {
19
- const { ora } = t.context;
20
- const task = sinon.spy();
15
+ const ora = t.mock.fn();
16
+ const task = t.mock.fn();
21
17
  const spinner = new Spinner({ container: { ora } });
22
18
  await spinner.show({ enabled: false, task });
23
- t.is(task.callCount, 0);
24
- t.is(ora.callCount, 0);
19
+ assert.equal(task.mock.callCount(), 0);
20
+ assert.equal(ora.mock.callCount(), 0);
25
21
  });
26
22
 
27
23
  test('should show spinner and run task by default', async t => {
28
- const { ora } = t.context;
29
- const task = sinon.stub().resolves();
24
+ const ora = t.mock.fn();
25
+ const task = t.mock.fn(() => Promise.resolve());
30
26
  const label = 'foo';
31
27
  const config = getConfig({ ci: true });
32
28
  const spinner = new Spinner({ container: { ora, config } });
33
29
  await spinner.show({ task, label });
34
- t.is(task.callCount, 1);
35
- t.is(ora.callCount, 1);
36
- t.is(ora.firstCall.args[0], task.firstCall.returnValue);
37
- t.is(ora.firstCall.args[1], label);
30
+ assert.equal(task.mock.callCount(), 1);
31
+ assert.equal(ora.mock.callCount(), 1);
32
+ assert.equal(ora.mock.calls[0].arguments[0], task.mock.calls[0].result);
33
+ assert.equal(ora.mock.calls[0].arguments[1], label);
38
34
  });
39
35
 
40
36
  test('should run task, but not show spinner if interactive', async t => {
41
- const { ora } = t.context;
42
- const task = sinon.stub().resolves();
37
+ const ora = t.mock.fn();
38
+ const task = t.mock.fn(() => Promise.resolve());
43
39
  const config = getConfig({ ci: false });
44
40
  const spinner = new Spinner({ container: { ora, config } });
45
41
  await spinner.show({ task });
46
- t.is(task.callCount, 1);
47
- t.is(ora.callCount, 0);
42
+ assert.equal(task.mock.callCount(), 1);
43
+ assert.equal(ora.mock.callCount(), 0);
48
44
  });
49
45
 
50
46
  test('should run task and show spinner if interactive, but external', async t => {
51
- const { ora } = t.context;
52
- const task = sinon.stub().resolves();
47
+ const ora = t.mock.fn();
48
+ const task = t.mock.fn(() => Promise.resolve());
53
49
  const config = getConfig({ ci: false });
54
50
  const spinner = new Spinner({ container: { ora, config } });
55
51
  await spinner.show({ task, external: true });
56
- t.is(task.callCount, 1);
57
- t.is(ora.callCount, 1);
52
+ assert.equal(task.mock.callCount(), 1);
53
+ assert.equal(ora.mock.callCount(), 1);
58
54
  });
@@ -1,30 +1,18 @@
1
- import nock from 'nock';
2
-
3
- const interceptAuthentication = ({ api = 'https://api.github.com', username = 'john' } = {}) => {
4
- nock(api).get('/user').reply(200, {
5
- login: username
6
- });
1
+ export const interceptAuthentication = (server, { username = 'john' } = {}) => {
2
+ server.get('/user', { status: 200, body: { login: username } });
7
3
  };
8
4
 
9
- const interceptCollaborator = ({
10
- api = 'https://api.github.com',
11
- owner = 'user',
12
- project = 'repo',
13
- username = 'john'
14
- } = {}) => {
15
- nock(api).get(`/repos/${owner}/${project}/collaborators/${username}`).reply(204);
5
+ export const interceptCollaborator = (server, { owner = 'user', project = 'repo', username = 'john' } = {}) => {
6
+ server.get(`/repos/${owner}/${project}/collaborators/${username}`, { status: 204 });
16
7
  };
17
8
 
18
- const interceptListReleases = ({
19
- host = 'github.com',
20
- api = 'https://api.github.com',
21
- owner = 'user',
22
- project = 'repo',
23
- tag_name
24
- } = {}) => {
25
- nock(api)
26
- .get(`/repos/${owner}/${project}/releases?per_page=1&page=1`)
27
- .reply(200, [
9
+ export const interceptListReleases = (
10
+ server,
11
+ { host = 'github.com', owner = 'user', project = 'repo', tag_name } = {}
12
+ ) => {
13
+ server.get(`/repos/${owner}/${project}/releases?per_page=1&page=1`, {
14
+ status: 200,
15
+ body: [
28
16
  {
29
17
  id: 1,
30
18
  upload_url: `https://uploads.${host}/repos/${owner}/${project}/releases/1/assets{?name,label}`,
@@ -36,39 +24,38 @@ const interceptListReleases = ({
36
24
  draft: false,
37
25
  prerelease: false
38
26
  }
39
- ]);
27
+ ]
28
+ });
40
29
  };
41
30
 
42
- const interceptCreate = ({
43
- api = 'https://api.github.com',
44
- host = 'github.com',
45
- owner = 'user',
46
- project = 'repo',
47
- body: {
48
- tag_name,
49
- name = '',
50
- body = null,
51
- prerelease = false,
52
- draft = false,
53
- generate_release_notes = false,
54
- make_latest = 'true',
55
- discussion_category_name = undefined
56
- }
57
- } = {}) => {
58
- nock(api)
59
- .post(`/repos/${owner}/${project}/releases`, {
31
+ export const interceptCreate = (
32
+ server,
33
+ {
34
+ api = 'https://api.github.com',
35
+ host = 'github.com',
36
+ owner = 'user',
37
+ project = 'repo',
38
+ body: {
60
39
  tag_name,
61
- name,
62
- body,
63
- prerelease,
64
- draft,
65
- generate_release_notes,
66
- make_latest,
67
- discussion_category_name
68
- })
69
- .reply(() => {
70
- const id = 1;
71
- const responseBody = {
40
+ name = '',
41
+ body = null,
42
+ prerelease = false,
43
+ draft = false,
44
+ generate_release_notes = false,
45
+ make_latest = 'true',
46
+ discussion_category_name = undefined
47
+ }
48
+ } = {}
49
+ ) => {
50
+ const id = 1;
51
+ server.post(
52
+ {
53
+ url: `/repos/${owner}/${project}/releases`,
54
+ body: { tag_name, name, body, prerelease, draft, generate_release_notes, make_latest, discussion_category_name }
55
+ },
56
+ {
57
+ status: 200,
58
+ body: {
72
59
  id,
73
60
  tag_name,
74
61
  name,
@@ -79,82 +66,85 @@ const interceptCreate = ({
79
66
  upload_url: `https://uploads.${host}/repos/${owner}/${project}/releases/${id}/assets{?name,label}`,
80
67
  html_url: `https://${host}/${owner}/${project}/releases/tag/${tag_name}`,
81
68
  discussion_url: discussion_category_name ? `https://${host}/${owner}/${project}/discussions/${id}` : undefined
82
- };
83
- return [200, responseBody, { location: `${api}/repos/${owner}/${project}/releases/${id}` }];
84
- });
69
+ },
70
+ headers: { location: `${api}/repos/${owner}/${project}/releases/${id}` }
71
+ }
72
+ );
85
73
  };
86
74
 
87
- const interceptUpdate = ({
88
- host = 'github.com',
89
- api = 'https://api.github.com',
90
- owner = 'user',
91
- project = 'repo',
92
- body: {
93
- tag_name,
94
- name = '',
95
- body = null,
96
- prerelease = false,
97
- draft = false,
98
- generate_release_notes = false,
99
- make_latest = 'true',
100
- discussion_category_name = undefined
101
- }
102
- } = {}) => {
103
- nock(api)
104
- .patch(`/repos/${owner}/${project}/releases/1`, {
105
- tag_name,
106
- name,
107
- body,
108
- draft,
109
- prerelease,
110
- generate_release_notes,
111
- make_latest,
112
- discussion_category_name
113
- })
114
- .reply(200, {
115
- id: 1,
75
+ export const interceptUpdate = (
76
+ server,
77
+ {
78
+ host = 'github.com',
79
+ owner = 'user',
80
+ project = 'repo',
81
+ body: {
116
82
  tag_name,
117
- name,
118
- body,
119
- prerelease,
120
- draft,
121
- generate_release_notes,
122
- upload_url: `https://uploads.${host}/repos/${owner}/${project}/releases/1/assets{?name,label}`,
123
- html_url: `https://${host}/${owner}/${project}/releases/tag/${tag_name}`
124
- });
83
+ name = '',
84
+ body = null,
85
+ prerelease = false,
86
+ draft = false,
87
+ generate_release_notes = false,
88
+ make_latest = 'true',
89
+ discussion_category_name = undefined
90
+ }
91
+ } = {}
92
+ ) => {
93
+ server.patch(
94
+ {
95
+ url: `/repos/${owner}/${project}/releases/1`,
96
+ body: {
97
+ tag_name,
98
+ name,
99
+ body,
100
+ draft,
101
+ prerelease,
102
+ generate_release_notes,
103
+ make_latest,
104
+ discussion_category_name
105
+ }
106
+ },
107
+ {
108
+ status: 200,
109
+ body: {
110
+ id: 1,
111
+ tag_name,
112
+ name,
113
+ body,
114
+ prerelease,
115
+ draft,
116
+ generate_release_notes,
117
+ upload_url: `https://uploads.${host}/repos/${owner}/${project}/releases/1/assets{?name,label}`,
118
+ html_url: `https://${host}/${owner}/${project}/releases/tag/${tag_name}`
119
+ }
120
+ }
121
+ );
125
122
  };
126
123
 
127
- const interceptAsset = ({
128
- api = 'https://api.github.com',
129
- host = 'github.com',
130
- owner = 'user',
131
- project = 'repo',
132
- tagName,
133
- body = {}
134
- } = {}) => {
135
- nock(`https://uploads.${host}`)
136
- .post(`/repos/${owner}/${project}/releases/1/assets`, body)
137
- .query(true)
138
- .reply(200, function () {
124
+ export const interceptAsset = (
125
+ server,
126
+ { api = 'https://api.github.com', host = 'github.com', owner = 'user', project = 'repo', tagName } = {}
127
+ ) => {
128
+ server.post(
129
+ {
130
+ url: `/repos/${owner}/${project}/releases/1/assets`
131
+ },
132
+ request => {
139
133
  const id = 1;
140
- const [, name] = this.req.path.match(/\?name=([^&]+)/);
134
+ const url = new URL(request.url);
135
+ const name = url.searchParams.get('name');
141
136
  return {
142
- id,
143
- url: `${api}/repos/${owner}/${project}/releases/assets/${id}`,
144
- name,
145
- label: '',
146
- state: 'uploaded',
147
- size: this.req.headers['content-length'],
148
- browser_download_url: `https://${host}/${owner}/${project}/releases/download/${tagName}/${name}`
137
+ status: 200,
138
+ body: {
139
+ id,
140
+ url: `${api}/repos/${owner}/${project}/releases/assets/${id}`,
141
+ name,
142
+ label: '',
143
+ state: 'uploaded',
144
+ size: request.headers['content-length'],
145
+ browser_download_url: `https://${host}/${owner}/${project}/releases/download/${tagName}/${name}`
146
+ }
149
147
  };
150
- });
151
- };
152
-
153
- export {
154
- interceptAuthentication,
155
- interceptCollaborator,
156
- interceptListReleases,
157
- interceptCreate,
158
- interceptUpdate,
159
- interceptAsset
148
+ }
149
+ );
160
150
  };
@@ -1,63 +1,87 @@
1
- import nock from 'nock';
1
+ export const interceptMembers = (server, { owner = 'emma' } = {}) => {
2
+ server.get(`/projects/john%2Frepo/members/all/1`, { status: 200, username: owner });
3
+ };
2
4
 
3
- export let interceptUser = ({ host = 'https://gitlab.com', owner = 'user' } = {}, options) =>
4
- nock(host, options).get('/api/v4/user').reply(200, { id: 1, username: owner });
5
+ export const interceptUser = (server, { owner = 'user' } = {}, options = {}) => {
6
+ server.get({ url: '/user', ...options }, { status: 200, body: { id: 1, username: owner } });
7
+ };
5
8
 
6
- export let interceptCollaborator = (
7
- { host = 'https://gitlab.com', owner = 'user', project = 'repo', group, userId = 1 } = {},
8
- options
9
+ export const interceptCollaborator = (
10
+ server,
11
+ { owner = 'user', project = 'repo', group, userId = 1 } = {},
12
+ options = {}
9
13
  ) =>
10
- nock(host, options)
11
- .get(`/api/v4/projects/${group ? `${group}%2F` : ''}${owner}%2F${project}/members/all/${userId}`)
12
- .reply(200, { id: userId, username: owner, access_level: 30 });
14
+ server.get(
15
+ {
16
+ url: `/projects/${group ? `${group}%2F` : ''}${owner}%2F${project}/members/all/${userId}`,
17
+ ...options
18
+ },
19
+ {
20
+ status: 200,
21
+ body: { id: userId, username: owner, access_level: 30 }
22
+ }
23
+ );
13
24
 
14
- export let interceptPublish = ({ host = 'https://gitlab.com', owner = 'user', project = 'repo', body } = {}, options) =>
15
- nock(host, options)
16
- .post(`/api/v4/projects/${owner}%2F${project}/releases`, body)
17
- .reply(200, {
18
- _links: {
19
- self: `https://gitlab.com/${owner}/${project}/-/releases/${body?.tag_name ?? '1.0.0'}`
25
+ export const interceptPublish = (server, { owner = 'user', project = 'repo', body } = {}) =>
26
+ server.post(
27
+ { url: `/projects/${owner}%2F${project}/releases`, body },
28
+ {
29
+ status: 200,
30
+ body: {
31
+ _links: {
32
+ self: `https://gitlab.com/${owner}/${project}/-/releases/${body?.tag_name ?? '1.0.0'}`
33
+ }
20
34
  }
21
- });
35
+ }
36
+ );
22
37
 
23
- export let interceptMilestones = (
24
- { host = 'https://gitlab.com', owner = 'user', project = 'repo', query = {}, milestones = [] } = {},
25
- options
26
- ) =>
27
- nock(host, options)
28
- .get(`/api/v4/projects/${owner}%2F${project}/milestones`)
29
- .query(
30
- Object.assign(
31
- {
32
- include_parent_milestones: true
33
- },
34
- query
35
- )
36
- )
37
- .reply(200, JSON.stringify(milestones));
38
+ export const interceptMilestones = (server, { owner = 'user', project = 'repo', query = {}, milestones = [] } = {}) =>
39
+ server.get(
40
+ {
41
+ url: `/projects/${owner}%2F${project}/milestones`,
42
+ query: {
43
+ include_parent_milestones: 'true',
44
+ ...query
45
+ }
46
+ },
47
+ {
48
+ status: 200,
49
+ body: milestones
50
+ }
51
+ );
38
52
 
39
- export let interceptAsset = ({ host = 'https://gitlab.com', owner = 'user', project = 'repo' } = {}) =>
40
- nock(host)
41
- .post(`/api/v4/projects/${owner}%2F${project}/uploads`)
42
- .query(true)
43
- .reply(200, (_, requestBody) => {
44
- const [, name] = requestBody.match(/filename="([^"]+)/);
53
+ export const interceptAsset = (server, { owner = 'user', project = 'repo' } = {}) =>
54
+ server.post(
55
+ {
56
+ url: `/projects/${owner}%2F${project}/uploads`
57
+ },
58
+ async request => {
59
+ const formData = await request.formData();
60
+ const { name } = formData.get('file');
45
61
  return {
46
- alt: name,
47
- url: `/uploads/7e8bec1fe27cc46a4bc6a91b9e82a07c/${name}`,
48
- full_path: `/-/project/1234/uploads/7e8bec1fe27cc46a4bc6a91b9e82a07c/${name}`,
49
- markdown: `[${name}](/uploads/7e8bec1fe27cc46a4bc6a91b9e82a07c/${name})`,
50
- _links: {
51
- self: `https://gitlab.com/${owner}/${project}/-/releases/${name}`
62
+ status: 200,
63
+ body: {
64
+ alt: name,
65
+ url: `/uploads/7e8bec1fe27cc46a4bc6a91b9e82a07c/${name}`,
66
+ full_path: `/-/project/1234/uploads/7e8bec1fe27cc46a4bc6a91b9e82a07c/${name}`,
67
+ markdown: `[${name}](/uploads/7e8bec1fe27cc46a4bc6a91b9e82a07c/${name})`,
68
+ _links: {
69
+ self: `https://gitlab.com/${owner}/${project}/-/releases/${name}`
70
+ }
52
71
  }
53
72
  };
54
- });
73
+ }
74
+ );
55
75
 
56
- export let interceptAssetGeneric = ({ host = 'https://gitlab.com', owner = 'user', project = 'repo' } = {}) =>
57
- nock(host)
58
- .put(`/api/v4/projects/${owner}%2F${project}/packages/generic/release-it/2.0.1/file-v2.0.1.txt`)
59
- .reply(200, () => {
60
- return {
76
+ export const interceptAssetGeneric = (server, { owner = 'user', project = 'repo' } = {}) =>
77
+ server.put(
78
+ {
79
+ url: `/projects/${owner}%2F${project}/packages/generic/release-it/2.0.1/file-v2.0.1.txt`
80
+ },
81
+ {
82
+ status: 200,
83
+ body: {
61
84
  message: '201 Created'
62
- };
63
- });
85
+ }
86
+ }
87
+ );