@apollo-annotation/cli 0.1.17 → 0.1.19

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.
Files changed (47) hide show
  1. package/README.md +120 -58
  2. package/bin/dev.js +2 -2
  3. package/bin/run.js +2 -2
  4. package/dist/ApolloConf.d.ts +22 -0
  5. package/dist/ApolloConf.js +144 -0
  6. package/dist/baseCommand.js +7 -17
  7. package/dist/commands/assembly/add-fasta.js +16 -27
  8. package/dist/commands/assembly/add-gff.js +11 -24
  9. package/dist/commands/assembly/check.js +7 -18
  10. package/dist/commands/assembly/delete.js +1 -1
  11. package/dist/commands/assembly/get.test.js +3 -3
  12. package/dist/commands/assembly/sequence.js +7 -21
  13. package/dist/commands/change/get.test.js +1 -1
  14. package/dist/commands/config.js +21 -53
  15. package/dist/commands/feature/add-child.js +21 -29
  16. package/dist/commands/feature/check.js +5 -5
  17. package/dist/commands/feature/copy.js +20 -32
  18. package/dist/commands/feature/delete.js +16 -31
  19. package/dist/commands/feature/edit-attribute.js +15 -10
  20. package/dist/commands/feature/edit-coords.js +39 -27
  21. package/dist/commands/feature/edit-type.js +5 -8
  22. package/dist/commands/feature/edit.js +3 -16
  23. package/dist/commands/feature/get-id.js +0 -1
  24. package/dist/commands/feature/get.js +6 -18
  25. package/dist/commands/feature/import.js +22 -41
  26. package/dist/commands/feature/search.js +1 -1
  27. package/dist/commands/login.js +17 -29
  28. package/dist/commands/logout.js +5 -14
  29. package/dist/commands/refseq/add-alias.d.ts +14 -0
  30. package/dist/commands/refseq/add-alias.js +72 -0
  31. package/dist/commands/status.js +5 -13
  32. package/dist/commands/user/get.test.js +1 -1
  33. package/dist/test/fixtures.js +2 -2
  34. package/dist/utils.d.ts +3 -3
  35. package/dist/utils.js +50 -25
  36. package/oclif.manifest.json +163 -102
  37. package/package.json +11 -3
  38. package/dist/Config.d.ts +0 -43
  39. package/dist/Config.js +0 -233
  40. package/dist/commands/config.test.d.ts +0 -1
  41. package/dist/commands/config.test.js +0 -188
  42. package/dist/commands/login.test.d.ts +0 -1
  43. package/dist/commands/login.test.js +0 -52
  44. package/dist/commands/logout.test.d.ts +0 -1
  45. package/dist/commands/logout.test.js +0 -67
  46. package/dist/commands/status.test.d.ts +0 -1
  47. package/dist/commands/status.test.js +0 -54
@@ -1,11 +1,10 @@
1
- /* eslint-disable @typescript-eslint/no-unsafe-assignment */
2
1
  /* eslint-disable @typescript-eslint/no-unnecessary-condition */
3
2
  import * as fs from 'node:fs';
4
3
  import * as path from 'node:path';
5
4
  import { Flags } from '@oclif/core';
6
5
  import { ObjectId } from 'bson';
7
6
  import { BaseCommand } from '../../baseCommand.js';
8
- import { submitAssembly, uploadFile, wrapLines } from '../../utils.js';
7
+ import { createFetchErrorMessage, submitAssembly, uploadFile, wrapLines, } from '../../utils.js';
9
8
  export default class Get extends BaseCommand {
10
9
  static description = 'Add new assembly from local or external fasta file';
11
10
  static examples = [
@@ -42,11 +41,10 @@ export default class Get extends BaseCommand {
42
41
  const access = await this.getAccess(flags['config-file'], flags.profile);
43
42
  const assemblyName = flags.assembly ?? path.basename(flags['input-file']);
44
43
  const isExternal = isValidHttpUrl(flags['input-file']);
45
- let response;
44
+ let res;
46
45
  if (isExternal) {
47
46
  if (flags.index === undefined) {
48
- this.logToStderr('Please provide the URL to the index of the external fasta file');
49
- this.exit(1);
47
+ this.error('Please provide the URL to the index of the external fasta file');
50
48
  }
51
49
  const body = {
52
50
  assemblyName,
@@ -56,34 +54,25 @@ export default class Get extends BaseCommand {
56
54
  fai: flags.index,
57
55
  },
58
56
  };
59
- response = (await submitAssembly(access.address, access.accessToken, body, flags.force));
57
+ res = (await submitAssembly(access.address, access.accessToken, body, flags.force));
60
58
  }
61
59
  else {
62
60
  if (!isExternal && !fs.existsSync(flags['input-file'])) {
63
- this.logToStderr(`File ${flags['input-file']} does not exist`);
64
- this.exit(1);
65
- }
66
- try {
67
- const fileId = await uploadFile(access.address, access.accessToken, flags['input-file'], 'text/x-fasta');
68
- const body = {
69
- assemblyName,
70
- fileId,
71
- typeName: 'AddAssemblyFromFileChange',
72
- assembly: new ObjectId().toHexString(),
73
- };
74
- response = (await submitAssembly(access.address, access.accessToken, body, flags.force));
75
- }
76
- catch (error) {
77
- this.logToStderr(error.message);
78
- this.exit(1);
61
+ this.error(`File ${flags['input-file']} does not exist`);
79
62
  }
63
+ const fileId = await uploadFile(access.address, access.accessToken, flags['input-file'], 'text/x-fasta');
64
+ const body = {
65
+ assemblyName,
66
+ fileId,
67
+ typeName: 'AddAssemblyFromFileChange',
68
+ assembly: new ObjectId().toHexString(),
69
+ };
70
+ res = (await submitAssembly(access.address, access.accessToken, body, flags.force));
80
71
  }
81
- if (!response.ok) {
82
- const json = JSON.parse(await response.text());
83
- this.logToStderr(JSON.stringify(json, null, 2));
84
- this.exit(1);
72
+ if (!res.ok) {
73
+ const errorMessage = await createFetchErrorMessage(res, 'Submit assembly failed');
74
+ throw new Error(errorMessage);
85
75
  }
86
- this.exit(0);
87
76
  }
88
77
  }
89
78
  function isValidHttpUrl(x) {
@@ -1,11 +1,9 @@
1
- /* eslint-disable @typescript-eslint/no-unsafe-member-access */
2
- /* eslint-disable @typescript-eslint/no-unsafe-assignment */
3
1
  import * as fs from 'node:fs';
4
2
  import * as path from 'node:path';
5
3
  import { Flags } from '@oclif/core';
6
4
  import { ObjectId } from 'bson';
7
5
  import { BaseCommand } from '../../baseCommand.js';
8
- import { submitAssembly, uploadFile, wrapLines } from '../../utils.js';
6
+ import { createFetchErrorMessage, submitAssembly, uploadFile, wrapLines, } from '../../utils.js';
9
7
  export default class AddGff extends BaseCommand {
10
8
  static summary = 'Add new assembly from gff or gft file';
11
9
  static description = wrapLines('The gff file is expected to contain sequences as per gff specifications. Features are also imported by default.');
@@ -41,8 +39,7 @@ export default class AddGff extends BaseCommand {
41
39
  async run() {
42
40
  const { flags } = await this.parse(AddGff);
43
41
  if (!fs.existsSync(flags['input-file'])) {
44
- this.logToStderr(`File ${flags['input-file']} does not exist`);
45
- this.exit(1);
42
+ this.error(`File ${flags['input-file']} does not exist`);
46
43
  }
47
44
  const access = await this.getAccess(flags['config-file'], flags.profile);
48
45
  const fileId = await uploadFile(access.address, access.accessToken, flags['input-file'], 'text/x-gff3');
@@ -51,26 +48,16 @@ export default class AddGff extends BaseCommand {
51
48
  typeName = 'AddAssemblyFromFileChange';
52
49
  }
53
50
  const assemblyName = flags.assembly ?? path.basename(flags['input-file']);
54
- let res;
55
- try {
56
- const body = {
57
- assemblyName,
58
- fileId,
59
- typeName,
60
- assembly: new ObjectId().toHexString(),
61
- };
62
- res = await submitAssembly(access.address, access.accessToken, body, flags.force);
63
- }
64
- catch (error) {
65
- this.logToStderr(error.message);
66
- this.exit(1);
67
- }
51
+ const body = {
52
+ assemblyName,
53
+ fileId,
54
+ typeName,
55
+ assembly: new ObjectId().toHexString(),
56
+ };
57
+ const res = await submitAssembly(access.address, access.accessToken, body, flags.force);
68
58
  if (!res.ok) {
69
- const json = JSON.parse(await res.text());
70
- const message = json['message'];
71
- this.logToStderr(message);
72
- this.exit(1);
59
+ const errorMessage = await createFetchErrorMessage(res, 'getFeatureById failed');
60
+ throw new Error(errorMessage);
73
61
  }
74
- this.exit(0);
75
62
  }
76
63
  }
@@ -1,7 +1,7 @@
1
1
  import { Flags } from '@oclif/core';
2
2
  import { fetch } from 'undici';
3
3
  import { BaseCommand } from '../../baseCommand.js';
4
- import { CheckError, convertCheckNameToId, createFetchErrorMessage, getAssembly, idReader, localhostToAddress, wrapLines, } from '../../utils.js';
4
+ import { convertCheckNameToId, createFetchErrorMessage, getAssembly, idReader, localhostToAddress, wrapLines, } from '../../utils.js';
5
5
  async function setChecks(address, accessToken, assembly, checkId) {
6
6
  const check = {
7
7
  _id: assembly,
@@ -55,7 +55,7 @@ function getCheckTypesForAssembly(checkTypes, assembly) {
55
55
  export default class Check extends BaseCommand {
56
56
  static summary = 'Add, view, or delete checks to assembly';
57
57
  static description = wrapLines('Manage checks, i.e. the rules ensuring features in an assembly are plausible. \
58
- This command only sets the check to apply, to retrieve features flagged by these checks use `apollo feature check`.');
58
+ This command only sets the checks to apply, to retrieve features flagged by these checks use `apollo feature check`.');
59
59
  static examples = [
60
60
  {
61
61
  description: 'View available check types:',
@@ -95,33 +95,23 @@ export default class Check extends BaseCommand {
95
95
  const checkTypes = await getCheckTypes(access.address, access.accessToken);
96
96
  if (flags.check === undefined && flags.assembly === undefined) {
97
97
  this.log(JSON.stringify(checkTypes, null, 2));
98
- this.exit(0);
98
+ return;
99
99
  }
100
100
  if (flags.assembly === undefined) {
101
- this.logToStderr('Please specify the assembly to manage for checks');
102
- this.exit(1);
101
+ this.error('Please specify the assembly to manage for checks');
103
102
  }
104
103
  const asm = idReader([flags.assembly]);
105
104
  const assembly = await getAssembly(access.address, access.accessToken, asm[0]);
106
105
  if (Object.keys(assembly).length === 0) {
107
- this.logToStderr(`Assembly ${flags.assembly} not found`);
108
- this.exit(1);
106
+ this.error(`Assembly ${flags.assembly} not found`);
109
107
  }
110
108
  const currentChecks = getCheckTypesForAssembly(checkTypes, assembly);
111
109
  if (flags.check === undefined) {
112
110
  this.log(JSON.stringify(currentChecks, null, 2));
113
- this.exit(0);
111
+ return;
114
112
  }
115
113
  let inputCheckIds = [];
116
- try {
117
- inputCheckIds = await convertCheckNameToId(access.address, access.accessToken, flags.check);
118
- }
119
- catch (error) {
120
- if (error instanceof CheckError) {
121
- this.logToStderr(error.message);
122
- this.exit(1);
123
- }
124
- }
114
+ inputCheckIds = await convertCheckNameToId(access.address, access.accessToken, flags.check);
125
115
  const newChecks = new Set();
126
116
  if (flags.delete) {
127
117
  const currentCheckIds = new Set();
@@ -143,6 +133,5 @@ export default class Check extends BaseCommand {
143
133
  }
144
134
  }
145
135
  await setChecks(access.address, access.accessToken, assembly['_id'], [...newChecks.values()]);
146
- this.exit(0);
147
136
  }
148
137
  }
@@ -38,6 +38,6 @@ export default class Delete extends BaseCommand {
38
38
  if (flags.verbose) {
39
39
  this.log(JSON.stringify(deleted, null, 2));
40
40
  }
41
- this.logToStderr(`${i} assemblies deleted`);
41
+ this.logToStderr(`${i} assemblies deleted`); // Keep as logToStderr
42
42
  }
43
43
  }
@@ -7,7 +7,7 @@ import { CONFIG_FILE, TEST_DATA_DIR, VERBOSE, copyFile, } from '../../test/fixtu
7
7
  const __dirname = fileURLToPath(new URL('.', import.meta.url));
8
8
  describe.skip('apollo assembly get: Fail without token', () => {
9
9
  before(() => {
10
- copyFile(`${TEST_DATA_DIR}/guest.yaml`, CONFIG_FILE, VERBOSE);
10
+ copyFile(`${TEST_DATA_DIR}/guest.yml`, CONFIG_FILE, VERBOSE);
11
11
  });
12
12
  after(() => {
13
13
  fs.rmSync(CONFIG_FILE);
@@ -24,7 +24,7 @@ describe.skip('apollo assembly get: Fail without token', () => {
24
24
  // TODO: Need valid token
25
25
  describe.skip('apollo assembly get: Get assemblies as YAML string', () => {
26
26
  before(() => {
27
- copyFile(`${TEST_DATA_DIR}/complete_config.yaml`, CONFIG_FILE, VERBOSE);
27
+ copyFile(`${TEST_DATA_DIR}/complete_config.yml`, CONFIG_FILE, VERBOSE);
28
28
  });
29
29
  after(() => {
30
30
  fs.rmSync(CONFIG_FILE);
@@ -38,7 +38,7 @@ describe.skip('apollo assembly get: Get assemblies as YAML string', () => {
38
38
  });
39
39
  });
40
40
  describe.skip('apollo assembly get: Test nock', () => {
41
- const cmd = ['assembly:get', '--config-file', 'tmp.yaml'];
41
+ const cmd = ['assembly:get', '--config-file', 'tmp.yml'];
42
42
  test
43
43
  .stdout()
44
44
  .nock('http://127.0.0.1:3999', (api) => api.persist().get('/assemblies').reply(200, { stuff: 'foo' }))
@@ -1,7 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/no-unsafe-argument */
2
- /* eslint-disable @typescript-eslint/restrict-template-expressions */
3
2
  import { Flags } from '@oclif/core';
4
- import { fetch } from 'undici';
3
+ import { Agent, fetch } from 'undici';
5
4
  import { BaseCommand } from '../../baseCommand.js';
6
5
  import { createFetchErrorMessage, getRefseqId, idReader, localhostToAddress, queryApollo, wrapLines, } from '../../utils.js';
7
6
  async function getSequence(address, accessToken, refSeq, start, end) {
@@ -13,15 +12,11 @@ async function getSequence(address, accessToken, refSeq, start, end) {
13
12
  });
14
13
  url.search = searchParams.toString();
15
14
  const uri = url.toString();
16
- const controller = new AbortController();
17
- setTimeout(() => {
18
- controller.abort();
19
- }, 24 * 60 * 60 * 1000);
20
15
  const auth = {
21
16
  headers: {
22
17
  authorization: `Bearer ${accessToken}`,
23
18
  },
24
- signal: controller.signal,
19
+ dispatcher: new Agent({ headersTimeout: 60 * 60 * 1000 }),
25
20
  };
26
21
  const response = await fetch(uri, auth);
27
22
  if (!response.ok) {
@@ -66,8 +61,7 @@ export default class ApolloCmd extends BaseCommand {
66
61
  const { flags } = await this.parse(ApolloCmd);
67
62
  const endCoord = flags.end ?? Number.MAX_SAFE_INTEGER;
68
63
  if (flags.start <= 0 || endCoord <= 0) {
69
- this.logToStderr('Start and end coordinates must be greater than 0.');
70
- this.exit(1);
64
+ this.error('Start and end coordinates must be greater than 0.');
71
65
  }
72
66
  const access = await this.getAccess(flags['config-file'], flags.profile);
73
67
  let assembly = undefined;
@@ -76,16 +70,9 @@ export default class ApolloCmd extends BaseCommand {
76
70
  [assembly] = idReader([flags.assembly]);
77
71
  }
78
72
  let refseqIds = [];
79
- try {
80
- refseqIds = await getRefseqId(access.address, access.accessToken, flags.refseq, assembly);
81
- }
82
- catch (error) {
83
- this.logToStderr(error.message);
84
- this.exit(1);
85
- }
73
+ refseqIds = await getRefseqId(access.address, access.accessToken, flags.refseq, assembly);
86
74
  if (refseqIds.length === 0) {
87
- this.logToStderr('No reference sequence found');
88
- this.exit(1);
75
+ this.error('No reference sequence found');
89
76
  }
90
77
  const refs = await queryApollo(access.address, access.accessToken, 'refSeqs');
91
78
  const refSeqs = (await refs.json());
@@ -95,8 +82,8 @@ export default class ApolloCmd extends BaseCommand {
95
82
  const seq = new TextDecoder().decode(seqObj?.value);
96
83
  let header = '';
97
84
  for (const x of refSeqs) {
98
- if (x['_id'] === rid) {
99
- const rname = x['name'];
85
+ if (x._id === rid) {
86
+ const rname = x.name;
100
87
  header = `>${rname}:${flags.start}..${flags.start + seq.length - 1}`;
101
88
  break;
102
89
  }
@@ -104,7 +91,6 @@ export default class ApolloCmd extends BaseCommand {
104
91
  this.log(header);
105
92
  this.log(splitStringIntoChunks(seq, 80).join('\n'));
106
93
  }
107
- this.exit(0);
108
94
  }
109
95
  }
110
96
  function splitStringIntoChunks(input, chunkSize) {
@@ -7,7 +7,7 @@ const __dirname = fileURLToPath(new URL('.', import.meta.url));
7
7
  // TODO: Need valid token
8
8
  describe.skip('apollo change get: Get changes as YAML string', () => {
9
9
  before(() => {
10
- copyFile(`${TEST_DATA_DIR}/complete_config.yaml`, CONFIG_FILE, VERBOSE);
10
+ copyFile(`${TEST_DATA_DIR}/complete_config.yml`, CONFIG_FILE, VERBOSE);
11
11
  });
12
12
  after(() => {
13
13
  fs.rmSync(CONFIG_FILE);
@@ -5,8 +5,8 @@ import password from '@inquirer/password';
5
5
  import select from '@inquirer/select';
6
6
  import { Args, Flags } from '@oclif/core';
7
7
  import { fetch } from 'undici';
8
+ import { ApolloConf, KEYS, optionDesc } from '../ApolloConf.js';
8
9
  import { BaseCommand } from '../baseCommand.js';
9
- import { Config, ConfigError, KEYS, optionDesc } from '../Config.js';
10
10
  import { createFetchErrorMessage, localhostToAddress, wrapLines, } from '../utils.js';
11
11
  export default class ApolloConfig extends BaseCommand {
12
12
  static summary = 'Get or set apollo configuration options';
@@ -53,13 +53,13 @@ export default class ApolloConfig extends BaseCommand {
53
53
  let configFile = flags['config-file'];
54
54
  configFile =
55
55
  configFile === undefined
56
- ? path.join(this.config.configDir, 'config.yaml')
56
+ ? path.join(this.config.configDir, 'config.yml')
57
57
  : path.resolve(configFile);
58
58
  if (flags['get-config-file']) {
59
59
  this.log(configFile);
60
- this.exit(0);
60
+ return;
61
61
  }
62
- const config = new Config(configFile);
62
+ const config = new ApolloConf(configFile);
63
63
  if (args.key === undefined) {
64
64
  await this.interactiveSetup(config, flags.profile);
65
65
  }
@@ -71,33 +71,16 @@ export default class ApolloConfig extends BaseCommand {
71
71
  if (flags.profile !== undefined) {
72
72
  profileName = flags.profile;
73
73
  }
74
- try {
75
- if (args.value === undefined) {
76
- const currentValue = config.get(args.key, profileName);
77
- this.log(currentValue);
78
- }
79
- else {
80
- config.set(args.key, args.value, profileName);
81
- }
74
+ if (args.value === undefined) {
75
+ const currentValue = config.get(`${profileName}.${args.key}`);
76
+ this.log(currentValue);
77
+ return;
82
78
  }
83
- catch (error) {
84
- if (error instanceof Error) {
85
- this.logToStderr(error.message);
86
- }
87
- this.exit(1);
79
+ if (args.key === 'accessType') {
80
+ config.setAccessType(profileName, args.value);
88
81
  }
89
- }
90
- const v = config.validate().error?.message;
91
- if (v) {
92
- this.logToStderr(v);
93
- }
94
- try {
95
- config.writeConfigFile();
96
- }
97
- catch (error) {
98
- if (error instanceof ConfigError) {
99
- this.logToStderr(error.message);
100
- this.exit(1);
82
+ else {
83
+ config.set(`${profileName}.${args.key}`, args.value);
101
84
  }
102
85
  }
103
86
  }
@@ -107,34 +90,19 @@ export default class ApolloConfig extends BaseCommand {
107
90
  }
108
91
  let setMe = true;
109
92
  while (setMe) {
110
- const address = await this.askAddress(config.get(KEYS[KEYS.address], profileName));
111
- try {
112
- config.set('address', address, profileName);
113
- setMe = false;
114
- }
115
- catch (error) {
116
- if (error instanceof ConfigError) {
117
- this.logToStderr(error.message);
118
- }
119
- }
93
+ const address = await this.askAddress(config.get(`${profileName}.${KEYS[KEYS.address]}`));
94
+ config.set(`${profileName}.${KEYS[KEYS.address]}`, address);
95
+ setMe = false;
120
96
  }
121
- const address = config.get(KEYS[KEYS.address], profileName);
97
+ const address = config.get(`${profileName}.${KEYS[KEYS.address]}`);
122
98
  let accessType = '';
123
- try {
124
- accessType = await this.selectAccessType(address);
125
- }
126
- catch (error) {
127
- if (error instanceof ConfigError) {
128
- this.logToStderr(error.message);
129
- this.exit(1);
130
- }
131
- }
132
- config.set(KEYS[KEYS.accessType], accessType, profileName);
99
+ accessType = await this.selectAccessType(address);
100
+ config.setAccessType(profileName, accessType);
133
101
  if (accessType === 'root') {
134
- const username = await this.askUsername(config.get(KEYS.rootCredentials_username, profileName));
135
- config.set('rootCredentials.username', username, profileName);
102
+ const username = await this.askUsername(config.get(`${profileName}.${KEYS.rootCredentials_username}`));
103
+ config.set(`${profileName}.rootCredentials.username`, username);
136
104
  const password = await this.askPassword();
137
- config.set('rootCredentials.password', password, profileName);
105
+ config.set(`${profileName}.rootCredentials.password`, password);
138
106
  }
139
107
  }
140
108
  async askProfileName(currentProfiles) {
@@ -1,6 +1,3 @@
1
- /* eslint-disable @typescript-eslint/restrict-template-expressions */
2
- /* eslint-disable @typescript-eslint/restrict-plus-operands */
3
- /* eslint-disable @typescript-eslint/no-unsafe-member-access */
4
1
  /* eslint-disable @typescript-eslint/no-unsafe-argument */
5
2
  /* eslint-disable @typescript-eslint/no-unsafe-assignment */
6
3
  import { Flags } from '@oclif/core';
@@ -42,44 +39,38 @@ export default class Get extends BaseCommand {
42
39
  async run() {
43
40
  const { flags } = await this.parse(Get);
44
41
  if (flags.end < flags.start) {
45
- this.logToStderr('Error: End coordinate is lower than the start coordinate');
46
- this.exit(1);
42
+ this.error('Error: End coordinate is lower than the start coordinate');
47
43
  }
48
44
  if (flags.start <= 0) {
49
- this.logToStderr('Coordinates must be greater than 0');
50
- this.exit(1);
45
+ this.error('Coordinates must be greater than 0');
51
46
  }
52
47
  const ff = idReader([flags['feature-id']]);
53
48
  if (ff.length !== 1) {
54
- this.logToStderr(`Expected only one feature identifier. Got ${ff.length}`);
49
+ this.error(`Expected only one feature identifier. Got ${ff.length}`);
55
50
  }
56
51
  const [featureId] = ff;
57
52
  const access = await this.getAccess(flags['config-file'], flags.profile);
58
- const response = await getFeatureById(access.address, access.accessToken, featureId);
59
- if (!response.ok) {
60
- const errorMessage = await createFetchErrorMessage(response, 'getFeatureById failed');
53
+ const res = await getFeatureById(access.address, access.accessToken, featureId);
54
+ if (!res.ok) {
55
+ const errorMessage = await createFetchErrorMessage(res, 'getFeatureById failed');
61
56
  throw new Error(errorMessage);
62
57
  }
63
- const feature = JSON.parse(await response.text());
58
+ const feature = JSON.parse(await res.text());
64
59
  const childRes = await this.addChild(access.address, access.accessToken, feature, flags.start - 1, flags.end, flags.type);
65
60
  if (!childRes.ok) {
66
- const obj = JSON.parse(await response.text());
67
- const message = obj['message'];
68
- this.logToStderr(message);
69
- this.exit(1);
61
+ const errorMessage = await createFetchErrorMessage(childRes, 'Add child failed');
62
+ throw new Error(errorMessage);
70
63
  }
71
- this.exit(0);
72
64
  }
73
- async addChild(address, accessToken, parentFeature, start, end, type) {
74
- const pStart = parentFeature['start'];
75
- const pEnd = parentFeature['end'];
76
- if (start < pStart || end > pEnd) {
77
- this.logToStderr(`Error: Child feature coordinates (${start + 1}-${end}) cannot extend beyond parent coordinates (${pStart + 1}-${pEnd})`);
78
- this.exit(1);
65
+ async addChild(address, accessToken, parentFeature, min, max, type) {
66
+ const pMin = parentFeature.min;
67
+ const pMax = parentFeature.max;
68
+ if (min < pMin || max > pMax) {
69
+ this.error(`Error: Child feature coordinates (${min + 1}-${max}) cannot extend beyond parent coordinates (${pMin + 1}-${pMax})`);
79
70
  }
80
71
  const res = await queryApollo(address, accessToken, 'refSeqs');
81
72
  const refSeqs = (await res.json());
82
- const refSeq = parentFeature['refSeq'];
73
+ const { refSeq } = parentFeature;
83
74
  let assembly = '';
84
75
  for (const x of refSeqs) {
85
76
  if (x['_id'] === refSeq) {
@@ -89,17 +80,18 @@ export default class Get extends BaseCommand {
89
80
  }
90
81
  const change = {
91
82
  typeName: 'AddFeatureChange',
92
- changedIds: [parentFeature['_id']],
83
+ // eslint-disable-next-line unicorn/consistent-destructuring
84
+ changedIds: [parentFeature._id],
93
85
  assembly,
94
86
  addedFeature: {
95
87
  _id: new ObjectId().toHexString(),
96
- gffId: '',
97
88
  refSeq,
98
- start,
99
- end,
89
+ min,
90
+ max,
100
91
  type,
101
92
  },
102
- parentFeatureId: parentFeature['_id'],
93
+ // eslint-disable-next-line unicorn/consistent-destructuring
94
+ parentFeatureId: parentFeature._id,
103
95
  };
104
96
  const url = new URL(localhostToAddress(`${address}/changes`));
105
97
  const auth = {
@@ -50,15 +50,15 @@ export default class Check extends BaseCommand {
50
50
  if (flags['feature-id'] === undefined) {
51
51
  keep = true;
52
52
  }
53
- else {
54
- for (const x of chk['ids']) {
55
- if (keepFeatures.has(x)) {
53
+ else if (chk.ids !== undefined) {
54
+ for (const x of chk.ids) {
55
+ if (x !== undefined && keepFeatures.has(x.toString())) {
56
56
  keep = true;
57
57
  break;
58
58
  }
59
59
  }
60
60
  }
61
- if (keep && refseqId.has(chk['refSeq'])) {
61
+ if (keep && refseqId.has(chk.refSeq)) {
62
62
  results.push(chk);
63
63
  }
64
64
  }
@@ -71,7 +71,7 @@ async function keepAssemblies(address, accessToken, assembly) {
71
71
  const res = await queryApollo(address, accessToken, 'assemblies');
72
72
  const asm = (await res.json());
73
73
  for (const x of asm) {
74
- keepAssembly.push(x['_id']);
74
+ keepAssembly.push(x._id);
75
75
  }
76
76
  }
77
77
  else {
@@ -38,42 +38,31 @@ export default class Copy extends BaseCommand {
38
38
  async run() {
39
39
  const { flags } = await this.parse(Copy);
40
40
  if (flags.start <= 0) {
41
- this.logToStderr('Start coordinate must be greater than 0');
42
- this.exit(1);
41
+ this.error('Start coordinate must be greater than 0');
43
42
  }
44
43
  const access = await this.getAccess(flags['config-file'], flags.profile);
45
- const response = await getFeatureById(access.address, access.accessToken, flags['feature-id']);
46
- if (!response.ok) {
47
- const errorMessage = await createFetchErrorMessage(response, 'getFeatureById failed');
44
+ const res = await getFeatureById(access.address, access.accessToken, flags['feature-id']);
45
+ if (!res.ok) {
46
+ const errorMessage = await createFetchErrorMessage(res, 'getFeatureById failed');
48
47
  throw new Error(errorMessage);
49
48
  }
50
- const feature = (await response.json());
49
+ const feature = (await res.json());
51
50
  let refseqIds = [];
52
- try {
53
- refseqIds = await getRefseqId(access.address, access.accessToken, flags.refseq, flags.assembly);
54
- }
55
- catch (error) {
56
- this.logToStderr(error.message);
57
- this.exit(1);
58
- }
51
+ refseqIds = await getRefseqId(access.address, access.accessToken, flags.refseq, flags.assembly);
59
52
  if (refseqIds.length === 0) {
60
- this.logToStderr('No reference sequence found');
61
- this.exit(1);
53
+ this.error('No reference sequence found');
62
54
  }
63
55
  const [refseq] = refseqIds;
64
56
  const assembly = await getAssemblyFromRefseq(access.address, access.accessToken, refseq);
65
57
  const newId = new ObjectId().toHexString();
66
58
  const rescopy = await this.copyFeature(access.address, access.accessToken, feature, refseq, flags.start, assembly, newId);
67
59
  if (!rescopy.ok) {
68
- const message = feature['message'];
69
- this.logToStderr(message);
70
- this.exit(1);
60
+ const errorMessage = await createFetchErrorMessage(rescopy, 'Copy feature failed');
61
+ throw new Error(errorMessage);
71
62
  }
72
- this.exit(0);
73
63
  }
74
- async copyFeature(address, accessToken, feature, refseq, start, assembly, newId) {
75
- const featureLen = feature['end'] -
76
- feature['start'];
64
+ async copyFeature(address, accessToken, feature, refseq, min, assembly, newId) {
65
+ const featureLen = feature.max - feature.min;
77
66
  const change = {
78
67
  typeName: 'AddFeatureChange',
79
68
  changedIds: [newId],
@@ -81,12 +70,11 @@ export default class Copy extends BaseCommand {
81
70
  addedFeature: {
82
71
  _id: newId,
83
72
  refSeq: refseq,
84
- start: start - 1,
85
- end: start + featureLen - 1,
86
- type: feature['type'],
87
- attributes: feature['attributes'],
88
- discontinuousLocations: feature['discontinuousLocations'],
89
- strand: feature['strand'],
73
+ min: min - 1,
74
+ max: min + featureLen - 1,
75
+ type: feature.type,
76
+ attributes: feature.attributes,
77
+ strand: feature.strand,
90
78
  },
91
79
  copyFeature: true,
92
80
  allIds: [newId],
@@ -100,11 +88,11 @@ export default class Copy extends BaseCommand {
100
88
  'Content-Type': 'application/json',
101
89
  },
102
90
  };
103
- const response = await fetch(url, auth);
104
- if (!response.ok) {
105
- const errorMessage = await createFetchErrorMessage(response, 'copyFeature failed');
91
+ const res = await fetch(url, auth);
92
+ if (!res.ok) {
93
+ const errorMessage = await createFetchErrorMessage(res, 'copyFeature failed');
106
94
  throw new Error(errorMessage);
107
95
  }
108
- return response;
96
+ return res;
109
97
  }
110
98
  }