@jbrowse/cli 3.7.0 → 4.0.0

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 (58) hide show
  1. package/README.md +4 -0
  2. package/bin/run +0 -0
  3. package/bundle/index.js +2280 -2722
  4. package/dist/bin.js +2 -2
  5. package/dist/commands/{add-assembly.js → add-assembly/index.js} +10 -10
  6. package/dist/commands/{assembly-utils.js → add-assembly/utils.js} +69 -105
  7. package/dist/commands/add-connection.js +10 -15
  8. package/dist/commands/add-track-json.js +26 -31
  9. package/dist/commands/add-track-utils/track-config.js +3 -15
  10. package/dist/commands/add-track-utils/validators.js +4 -9
  11. package/dist/commands/add-track.js +23 -25
  12. package/dist/commands/{admin-server.js → admin-server/index.js} +9 -9
  13. package/dist/commands/{admin-server-utils.js → admin-server/utils.js} +7 -16
  14. package/dist/commands/create.js +8 -8
  15. package/dist/commands/{make-pif.js → make-pif/index.js} +11 -17
  16. package/dist/commands/{make-pif-utils → make-pif}/pif-generator.js +6 -6
  17. package/dist/commands/{sort-bed-utils/process-utils.js → process-utils.js} +0 -10
  18. package/dist/commands/remove-track.js +6 -11
  19. package/dist/commands/set-default-session.js +8 -12
  20. package/dist/commands/shared/config-operations.js +37 -0
  21. package/dist/commands/shared/sort-utils.js +57 -0
  22. package/dist/commands/shared/validators.js +18 -0
  23. package/dist/commands/sort-bed.js +13 -24
  24. package/dist/commands/sort-gff.js +13 -24
  25. package/dist/commands/text-index/adapter-utils.js +43 -0
  26. package/dist/commands/text-index/aggregate.js +52 -0
  27. package/dist/commands/{text-index.js → text-index/command.js} +13 -6
  28. package/dist/commands/text-index/config-utils.js +134 -0
  29. package/dist/commands/{text-index-utils → text-index}/file-list.js +12 -15
  30. package/dist/commands/text-index/index.js +11 -0
  31. package/dist/commands/{text-index-utils → text-index}/indexing-utils.js +30 -20
  32. package/dist/commands/text-index/per-track.js +54 -0
  33. package/dist/commands/track-utils.js +33 -33
  34. package/dist/commands/upgrade.js +8 -8
  35. package/dist/index.js +39 -27
  36. package/dist/types/common.js +9 -8
  37. package/dist/types/gff3Adapter.js +17 -48
  38. package/dist/types/streamUtils.js +66 -0
  39. package/dist/types/vcfAdapter.js +17 -54
  40. package/dist/util.js +14 -7
  41. package/dist/utils.js +10 -5
  42. package/package.json +14 -17
  43. package/dist/commands/make-pif-utils/validators.js +0 -22
  44. package/dist/commands/sort-bed-utils/constants.js +0 -12
  45. package/dist/commands/sort-bed-utils/sort-utils.js +0 -24
  46. package/dist/commands/sort-bed-utils/validators.js +0 -22
  47. package/dist/commands/sort-gff-utils/constants.js +0 -13
  48. package/dist/commands/sort-gff-utils/process-utils.js +0 -23
  49. package/dist/commands/sort-gff-utils/sort-utils.js +0 -55
  50. package/dist/commands/sort-gff-utils/validators.js +0 -21
  51. package/dist/commands/text-index-utils/adapter-utils.js +0 -63
  52. package/dist/commands/text-index-utils/aggregate.js +0 -87
  53. package/dist/commands/text-index-utils/config-utils.js +0 -59
  54. package/dist/commands/text-index-utils/index.js +0 -9
  55. package/dist/commands/text-index-utils/per-track.js +0 -65
  56. /package/dist/commands/{make-pif-utils → make-pif}/cigar-utils.js +0 -0
  57. /package/dist/commands/{make-pif-utils → make-pif}/file-utils.js +0 -0
  58. /package/dist/commands/{text-index-utils → text-index}/validators.js +0 -0
package/dist/bin.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- const index_1 = require("./index");
5
- (0, index_1.main)(process.argv.slice(2)).catch((e) => {
4
+ const index_ts_1 = require("./index.js");
5
+ (0, index_ts_1.main)(process.argv.slice(2)).catch((e) => {
6
6
  console.error(e);
7
7
  });
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.run = run;
4
4
  const util_1 = require("util");
5
- const utils_1 = require("../utils");
6
- const assembly_utils_1 = require("./assembly-utils");
5
+ const utils_ts_1 = require("./utils.js");
6
+ const utils_ts_2 = require("../../utils.js");
7
7
  async function run(args) {
8
8
  const options = {
9
9
  type: {
@@ -114,7 +114,7 @@ async function run(args) {
114
114
  '$ jbrowse add-assembly myfile.fa.gz --load copy',
115
115
  ];
116
116
  if (runFlags.help) {
117
- (0, utils_1.printHelp)({
117
+ (0, utils_ts_2.printHelp)({
118
118
  description,
119
119
  examples,
120
120
  usage: 'jbrowse add-assembly <sequence> [options]',
@@ -124,17 +124,17 @@ async function run(args) {
124
124
  }
125
125
  const argsSequence = positionals[0] || '';
126
126
  const output = runFlags.target || runFlags.out || '.';
127
- (0, utils_1.debug)(`Sequence location is: ${argsSequence}`);
128
- const target = await (0, assembly_utils_1.resolveTargetPath)(output);
129
- const baseAssembly = await (0, assembly_utils_1.getAssembly)({ runFlags, argsSequence, target });
130
- const assembly = await (0, assembly_utils_1.enhanceAssembly)(baseAssembly, runFlags);
131
- const configContents = await (0, assembly_utils_1.loadOrCreateConfig)(target);
132
- const { config: updatedConfig, wasOverwritten } = await (0, assembly_utils_1.addAssemblyToConfig)({
127
+ (0, utils_ts_2.debug)(`Sequence location is: ${argsSequence}`);
128
+ const target = await (0, utils_ts_1.resolveTargetPath)(output);
129
+ const baseAssembly = await (0, utils_ts_1.getAssembly)({ runFlags, argsSequence, target });
130
+ const assembly = await (0, utils_ts_1.enhanceAssembly)(baseAssembly, runFlags);
131
+ const configContents = await (0, utils_ts_1.loadOrCreateConfig)(target);
132
+ const { config: updatedConfig, wasOverwritten } = await (0, utils_ts_1.addAssemblyToConfig)({
133
133
  config: configContents,
134
134
  assembly,
135
135
  runFlags,
136
136
  });
137
- await (0, assembly_utils_1.saveConfigAndReport)({
137
+ await (0, utils_ts_1.saveConfigAndReport)({
138
138
  config: updatedConfig,
139
139
  target,
140
140
  assembly,
@@ -17,7 +17,9 @@ exports.addAssemblyToConfig = addAssemblyToConfig;
17
17
  exports.saveConfigAndReport = saveConfigAndReport;
18
18
  const fs_1 = __importDefault(require("fs"));
19
19
  const path_1 = __importDefault(require("path"));
20
- const utils_1 = require("../utils");
20
+ const common_ts_1 = require("../../types/common.js");
21
+ const utils_ts_1 = require("../../utils.js");
22
+ const config_operations_ts_1 = require("../shared/config-operations.js");
21
23
  const { rename, copyFile, symlink } = fs_1.default.promises;
22
24
  function isValidJSON(string) {
23
25
  try {
@@ -54,60 +56,26 @@ function guessSequenceType(sequence) {
54
56
  throw new Error('Could not determine sequence type automatically, add --type to specify it');
55
57
  }
56
58
  function needLoadData(location) {
57
- let locationUrl;
58
- try {
59
- locationUrl = new URL(location);
60
- }
61
- catch (error) {
62
- // ignore
63
- }
64
- if (locationUrl) {
65
- return false;
66
- }
67
- return true;
59
+ return !(0, common_ts_1.isURL)(location);
68
60
  }
69
61
  async function loadData({ load, filePaths, destination, }) {
70
- let locationUrl;
71
- try {
72
- locationUrl = new URL(filePaths[0]);
73
- }
74
- catch (error) {
75
- // ignore
62
+ if ((0, common_ts_1.isURL)(filePaths[0])) {
63
+ return false;
76
64
  }
77
- if (locationUrl) {
65
+ if (load === 'inPlace') {
78
66
  return false;
79
67
  }
80
- switch (load) {
81
- case 'copy': {
82
- await Promise.all(filePaths.map(async (filePath) => {
83
- if (!filePath) {
84
- return undefined;
85
- }
86
- return copyFile(filePath, path_1.default.join(path_1.default.dirname(destination), path_1.default.basename(filePath)));
87
- }));
88
- return true;
89
- }
90
- case 'symlink': {
91
- await Promise.all(filePaths.map(async (filePath) => {
92
- if (!filePath) {
93
- return undefined;
94
- }
95
- return symlink(path_1.default.resolve(filePath), path_1.default.join(path_1.default.dirname(destination), path_1.default.basename(filePath)));
96
- }));
97
- return true;
98
- }
99
- case 'move': {
100
- await Promise.all(filePaths.map(async (filePath) => {
101
- if (!filePath) {
102
- return undefined;
103
- }
104
- return rename(filePath, path_1.default.join(path_1.default.dirname(destination), path_1.default.basename(filePath)));
105
- }));
106
- return true;
107
- }
108
- case 'inPlace': {
109
- return false;
110
- }
68
+ const destDir = path_1.default.dirname(destination);
69
+ const validPaths = filePaths.filter(f => !!f);
70
+ const operations = {
71
+ copy: copyFile,
72
+ symlink: (src, dest) => symlink(path_1.default.resolve(src), dest),
73
+ move: rename,
74
+ };
75
+ const operation = operations[load];
76
+ if (operation) {
77
+ await Promise.all(validPaths.map(filePath => operation(filePath, path_1.default.join(destDir, path_1.default.basename(filePath)))));
78
+ return true;
111
79
  }
112
80
  return false;
113
81
  }
@@ -122,25 +90,25 @@ async function getAssembly({ runFlags, argsSequence, target, }) {
122
90
  let { name } = runFlags;
123
91
  let { type } = runFlags;
124
92
  if (type) {
125
- (0, utils_1.debug)(`Type is: ${type}`);
93
+ (0, utils_ts_1.debug)(`Type is: ${type}`);
126
94
  }
127
95
  else {
128
96
  type = guessSequenceType(argsSequence);
129
- (0, utils_1.debug)(`No type specified, guessing type: ${type}`);
97
+ (0, utils_ts_1.debug)(`No type specified, guessing type: ${type}`);
130
98
  }
131
99
  if (name) {
132
- (0, utils_1.debug)(`Name is: ${name}`);
100
+ (0, utils_ts_1.debug)(`Name is: ${name}`);
133
101
  }
134
102
  switch (type) {
135
103
  case 'indexedFasta': {
136
104
  const { skipCheck, force, load, faiLocation } = runFlags;
137
- let sequenceLocation = await (0, utils_1.resolveFileLocation)(argsSequence, !(skipCheck || force), load === 'inPlace');
138
- (0, utils_1.debug)(`FASTA location resolved to: ${sequenceLocation}`);
139
- let indexLocation = await (0, utils_1.resolveFileLocation)(faiLocation || `${argsSequence}.fai`, !(skipCheck || force), load === 'inPlace');
140
- (0, utils_1.debug)(`FASTA index location resolved to: ${indexLocation}`);
105
+ let sequenceLocation = await (0, utils_ts_1.resolveFileLocation)(argsSequence, !(skipCheck || force), load === 'inPlace');
106
+ (0, utils_ts_1.debug)(`FASTA location resolved to: ${sequenceLocation}`);
107
+ let indexLocation = await (0, utils_ts_1.resolveFileLocation)(faiLocation || `${argsSequence}.fai`, !(skipCheck || force), load === 'inPlace');
108
+ (0, utils_ts_1.debug)(`FASTA index location resolved to: ${indexLocation}`);
141
109
  if (!name) {
142
110
  name = path_1.default.basename(sequenceLocation, sequenceLocation.endsWith('.fasta') ? '.fasta' : '.fa');
143
- (0, utils_1.debug)(`Guessing name: ${name}`);
111
+ (0, utils_ts_1.debug)(`Guessing name: ${name}`);
144
112
  }
145
113
  const loaded = load
146
114
  ? await loadData({
@@ -168,15 +136,15 @@ async function getAssembly({ runFlags, argsSequence, target, }) {
168
136
  break;
169
137
  }
170
138
  case 'bgzipFasta': {
171
- let sequenceLocation = await (0, utils_1.resolveFileLocation)(argsSequence, !(runFlags.skipCheck || runFlags.force), runFlags.load === 'inPlace');
172
- (0, utils_1.debug)(`compressed FASTA location resolved to: ${sequenceLocation}`);
173
- let indexLocation = await (0, utils_1.resolveFileLocation)(runFlags.faiLocation || `${sequenceLocation}.fai`, !(runFlags.skipCheck || runFlags.force), runFlags.load === 'inPlace');
174
- (0, utils_1.debug)(`compressed FASTA index location resolved to: ${indexLocation}`);
175
- let bgzipIndexLocation = await (0, utils_1.resolveFileLocation)(runFlags.gziLocation || `${sequenceLocation}.gzi`, !(runFlags.skipCheck || runFlags.force), runFlags.load === 'inPlace');
176
- (0, utils_1.debug)(`bgzip index location resolved to: ${bgzipIndexLocation}`);
139
+ let sequenceLocation = await (0, utils_ts_1.resolveFileLocation)(argsSequence, !(runFlags.skipCheck || runFlags.force), runFlags.load === 'inPlace');
140
+ (0, utils_ts_1.debug)(`compressed FASTA location resolved to: ${sequenceLocation}`);
141
+ let indexLocation = await (0, utils_ts_1.resolveFileLocation)(runFlags.faiLocation || `${sequenceLocation}.fai`, !(runFlags.skipCheck || runFlags.force), runFlags.load === 'inPlace');
142
+ (0, utils_ts_1.debug)(`compressed FASTA index location resolved to: ${indexLocation}`);
143
+ let bgzipIndexLocation = await (0, utils_ts_1.resolveFileLocation)(runFlags.gziLocation || `${sequenceLocation}.gzi`, !(runFlags.skipCheck || runFlags.force), runFlags.load === 'inPlace');
144
+ (0, utils_ts_1.debug)(`bgzip index location resolved to: ${bgzipIndexLocation}`);
177
145
  if (!name) {
178
146
  name = path_1.default.basename(sequenceLocation, sequenceLocation.endsWith('.fasta.gz') ? '.fasta.gz' : '.fa.gz');
179
- (0, utils_1.debug)(`Guessing name: ${name}`);
147
+ (0, utils_ts_1.debug)(`Guessing name: ${name}`);
180
148
  }
181
149
  const loaded = runFlags.load
182
150
  ? await loadData({
@@ -209,11 +177,11 @@ async function getAssembly({ runFlags, argsSequence, target, }) {
209
177
  break;
210
178
  }
211
179
  case 'twoBit': {
212
- let sequenceLocation = await (0, utils_1.resolveFileLocation)(argsSequence, !(runFlags.skipCheck || runFlags.force), runFlags.load === 'inPlace');
213
- (0, utils_1.debug)(`2bit location resolved to: ${sequenceLocation}`);
180
+ let sequenceLocation = await (0, utils_ts_1.resolveFileLocation)(argsSequence, !(runFlags.skipCheck || runFlags.force), runFlags.load === 'inPlace');
181
+ (0, utils_ts_1.debug)(`2bit location resolved to: ${sequenceLocation}`);
214
182
  if (!name) {
215
183
  name = path_1.default.basename(sequenceLocation, '.2bit');
216
- (0, utils_1.debug)(`Guessing name: ${name}`);
184
+ (0, utils_ts_1.debug)(`Guessing name: ${name}`);
217
185
  }
218
186
  const loaded = runFlags.load
219
187
  ? await loadData({
@@ -239,11 +207,11 @@ async function getAssembly({ runFlags, argsSequence, target, }) {
239
207
  break;
240
208
  }
241
209
  case 'chromSizes': {
242
- let sequenceLocation = await (0, utils_1.resolveFileLocation)(argsSequence, !(runFlags.skipCheck || runFlags.force), runFlags.load === 'inPlace');
243
- (0, utils_1.debug)(`chrom.sizes location resolved to: ${sequenceLocation}`);
210
+ let sequenceLocation = await (0, utils_ts_1.resolveFileLocation)(argsSequence, !(runFlags.skipCheck || runFlags.force), runFlags.load === 'inPlace');
211
+ (0, utils_ts_1.debug)(`chrom.sizes location resolved to: ${sequenceLocation}`);
244
212
  if (!name) {
245
213
  name = path_1.default.basename(sequenceLocation, '.chrom.sizes');
246
- (0, utils_1.debug)(`Guessing name: ${name}`);
214
+ (0, utils_ts_1.debug)(`Guessing name: ${name}`);
247
215
  }
248
216
  const loaded = runFlags.load
249
217
  ? await loadData({
@@ -269,8 +237,8 @@ async function getAssembly({ runFlags, argsSequence, target, }) {
269
237
  break;
270
238
  }
271
239
  case 'custom': {
272
- const adapter = await (0, utils_1.readInlineOrFileJson)(argsSequence);
273
- (0, utils_1.debug)(`Custom adapter: ${JSON.stringify(adapter)}`);
240
+ const adapter = await (0, utils_ts_1.readInlineOrFileJson)(argsSequence);
241
+ (0, utils_ts_1.debug)(`Custom adapter: ${JSON.stringify(adapter)}`);
274
242
  if (!name) {
275
243
  if (isValidJSON(argsSequence)) {
276
244
  throw new Error('Must provide --name when using custom inline JSON sequence');
@@ -278,7 +246,7 @@ async function getAssembly({ runFlags, argsSequence, target, }) {
278
246
  else {
279
247
  name = path_1.default.basename(argsSequence, '.json');
280
248
  }
281
- (0, utils_1.debug)(`Guessing name: ${name}`);
249
+ (0, utils_ts_1.debug)(`Guessing name: ${name}`);
282
250
  }
283
251
  if (!('type' in adapter)) {
284
252
  throw new Error(`No "type" specified in sequence adapter "${JSON.stringify(adapter)}"`);
@@ -317,7 +285,7 @@ async function resolveTargetPath(output) {
317
285
  async function enhanceAssembly(assembly, runFlags) {
318
286
  const enhancedAssembly = { ...assembly };
319
287
  if (runFlags.alias?.length) {
320
- (0, utils_1.debug)(`Adding assembly aliases: ${runFlags.alias}`);
288
+ (0, utils_ts_1.debug)(`Adding assembly aliases: ${runFlags.alias}`);
321
289
  enhancedAssembly.aliases = runFlags.alias;
322
290
  }
323
291
  if (runFlags.refNameColors) {
@@ -328,18 +296,18 @@ async function enhanceAssembly(assembly, runFlags) {
328
296
  if (runFlags.refNameAliases) {
329
297
  if (runFlags.refNameAliasesType &&
330
298
  runFlags.refNameAliasesType === 'custom') {
331
- const refNameAliasesConfig = await (0, utils_1.readInlineOrFileJson)(runFlags.refNameAliases);
299
+ const refNameAliasesConfig = await (0, utils_ts_1.readInlineOrFileJson)(runFlags.refNameAliases);
332
300
  if (!refNameAliasesConfig.type) {
333
301
  throw new Error(`No "type" specified in refNameAliases adapter "${JSON.stringify(refNameAliasesConfig)}"`);
334
302
  }
335
- (0, utils_1.debug)(`Adding custom refNameAliases config: ${JSON.stringify(refNameAliasesConfig)}`);
303
+ (0, utils_ts_1.debug)(`Adding custom refNameAliases config: ${JSON.stringify(refNameAliasesConfig)}`);
336
304
  enhancedAssembly.refNameAliases = {
337
305
  adapter: refNameAliasesConfig,
338
306
  };
339
307
  }
340
308
  else {
341
- const refNameAliasesLocation = await (0, utils_1.resolveFileLocation)(runFlags.refNameAliases, !(runFlags.skipCheck || runFlags.force), runFlags.load === 'inPlace');
342
- (0, utils_1.debug)(`refName aliases file location resolved to: ${refNameAliasesLocation}`);
309
+ const refNameAliasesLocation = await (0, utils_ts_1.resolveFileLocation)(runFlags.refNameAliases, !(runFlags.skipCheck || runFlags.force), runFlags.load === 'inPlace');
310
+ (0, utils_ts_1.debug)(`refName aliases file location resolved to: ${refNameAliasesLocation}`);
343
311
  enhancedAssembly.refNameAliases = {
344
312
  adapter: {
345
313
  type: 'RefNameAliasAdapter',
@@ -370,41 +338,37 @@ function createDefaultConfig() {
370
338
  async function loadOrCreateConfig(target) {
371
339
  const defaultConfig = createDefaultConfig();
372
340
  if (fs_1.default.existsSync(target)) {
373
- (0, utils_1.debug)(`Found existing config file ${target}`);
341
+ (0, utils_ts_1.debug)(`Found existing config file ${target}`);
374
342
  return {
375
343
  ...defaultConfig,
376
- ...(await (0, utils_1.readJsonFile)(target)),
344
+ ...(await (0, utils_ts_1.readJsonFile)(target)),
377
345
  };
378
346
  }
379
347
  else {
380
- (0, utils_1.debug)(`Creating config file ${target}`);
348
+ (0, utils_ts_1.debug)(`Creating config file ${target}`);
381
349
  return { ...defaultConfig };
382
350
  }
383
351
  }
384
352
  async function addAssemblyToConfig({ config, assembly, runFlags, }) {
385
- const updatedConfig = { ...config };
386
- if (!updatedConfig.assemblies) {
387
- updatedConfig.assemblies = [];
388
- }
389
- const idx = updatedConfig.assemblies.findIndex(configAssembly => configAssembly.name === assembly.name);
390
- if (idx !== -1) {
391
- (0, utils_1.debug)(`Found existing assembly ${assembly.name} in configuration`);
392
- if (runFlags.overwrite || runFlags.force) {
393
- (0, utils_1.debug)(`Overwriting assembly ${assembly.name} in configuration`);
394
- updatedConfig.assemblies[idx] = assembly;
395
- return { config: updatedConfig, wasOverwritten: true };
396
- }
397
- else {
398
- throw new Error(`Cannot add assembly with name ${assembly.name}, an assembly with that name already exists`);
399
- }
400
- }
401
- else {
402
- updatedConfig.assemblies.push(assembly);
403
- return { config: updatedConfig, wasOverwritten: false };
404
- }
353
+ const { updatedItems, wasOverwritten } = (0, config_operations_ts_1.findAndUpdateOrAdd)({
354
+ items: config.assemblies || [],
355
+ newItem: assembly,
356
+ idField: 'name',
357
+ getId: item => item.name,
358
+ allowOverwrite: runFlags.overwrite || runFlags.force || false,
359
+ itemType: 'assembly',
360
+ });
361
+ return {
362
+ config: { ...config, assemblies: updatedItems },
363
+ wasOverwritten,
364
+ };
405
365
  }
406
366
  async function saveConfigAndReport({ config, target, assembly, wasOverwritten, }) {
407
- (0, utils_1.debug)(`Writing configuration to file ${target}`);
408
- await (0, utils_1.writeJsonFile)(target, config);
409
- console.log(`${wasOverwritten ? 'Overwrote' : 'Added'} assembly "${assembly.name}" ${wasOverwritten ? 'in' : 'to'} ${target}`);
367
+ await (0, config_operations_ts_1.saveConfigAndReport)({
368
+ config,
369
+ target,
370
+ itemType: 'assembly',
371
+ itemName: assembly.name,
372
+ wasOverwritten,
373
+ });
410
374
  }
@@ -4,12 +4,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.run = run;
7
- const fs_1 = __importDefault(require("fs"));
8
7
  const path_1 = __importDefault(require("path"));
9
8
  const util_1 = require("util");
10
9
  const json_parse_better_errors_1 = __importDefault(require("json-parse-better-errors"));
11
- const fetchWithProxy_1 = __importDefault(require("../fetchWithProxy"));
12
- const utils_1 = require("../utils");
10
+ const fetchWithProxy_ts_1 = __importDefault(require("../fetchWithProxy.js"));
11
+ const utils_ts_1 = require("../utils.js");
13
12
  async function resolveURL(location, check = true) {
14
13
  let locationUrl;
15
14
  try {
@@ -19,7 +18,7 @@ async function resolveURL(location, check = true) {
19
18
  throw new Error(`The location ${location} provided is not a valid URL`);
20
19
  }
21
20
  if (check) {
22
- const response = await (0, fetchWithProxy_1.default)(`${locationUrl}`, { method: 'HEAD' });
21
+ const response = await (0, fetchWithProxy_ts_1.default)(`${locationUrl}`, { method: 'HEAD' });
23
22
  if (!response.ok) {
24
23
  throw new Error(`HTTP ${response.status} fetching ${locationUrl}`);
25
24
  }
@@ -102,7 +101,7 @@ async function run(args) {
102
101
  '$ jbrowse add-connection https://mysite.com/path/to/hub.txt --connectionId newId --name newName --target /path/to/jb2/installation/config.json',
103
102
  ];
104
103
  if (flags.help) {
105
- (0, utils_1.printHelp)({
104
+ (0, utils_ts_1.printHelp)({
106
105
  description,
107
106
  examples,
108
107
  usage: 'jbrowse add-connection <connectionUrlOrPath> [options]',
@@ -112,17 +111,13 @@ async function run(args) {
112
111
  }
113
112
  const connectionUrlOrPath = positionals[0];
114
113
  if (!connectionUrlOrPath) {
115
- console.error('Error: Missing required argument: connectionUrlOrPath');
116
- console.error('Usage: jbrowse add-connection <connectionUrlOrPath> [options]');
117
- process.exit(1);
114
+ throw new Error('Missing required argument: connectionUrlOrPath\nUsage: jbrowse add-connection <connectionUrlOrPath> [options]');
118
115
  }
119
- const output = flags.target || flags.out || '.';
120
- const isDir = fs_1.default.lstatSync(output).isDirectory();
121
- const target = isDir ? `${output}/config.json` : output;
116
+ const target = await (0, utils_ts_1.resolveConfigPath)(flags.target, flags.out);
122
117
  const { assemblyNames, type, name, config, connectionId, skipCheck, force } = flags;
123
118
  const url = await resolveURL(connectionUrlOrPath, !(skipCheck || force));
124
- const configContents = await (0, utils_1.readJsonFile)(target);
125
- (0, utils_1.debug)(`Using config file ${target}`);
119
+ const configContents = await (0, utils_ts_1.readJsonFile)(target);
120
+ (0, utils_ts_1.debug)(`Using config file ${target}`);
126
121
  if (!configContents.assemblies?.length) {
127
122
  throw new Error('No assemblies found. Please add one before adding connections');
128
123
  }
@@ -171,7 +166,7 @@ async function run(args) {
171
166
  else {
172
167
  configContents.connections.push(connectionConfig);
173
168
  }
174
- (0, utils_1.debug)(`Writing configuration to file ${target}`);
175
- await (0, utils_1.writeJsonFile)(target, configContents);
169
+ (0, utils_ts_1.debug)(`Writing configuration to file ${target}`);
170
+ await (0, utils_ts_1.writeJsonFile)(target, configContents);
176
171
  console.log(`${idx !== -1 ? 'Overwrote' : 'Added'} connection "${name || id}" ${idx !== -1 ? 'in' : 'to'} ${target}`);
177
172
  }
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.run = run;
4
- const fs_1 = require("fs");
5
4
  const util_1 = require("util");
6
- const utils_1 = require("../utils");
5
+ const utils_ts_1 = require("../utils.js");
6
+ const config_operations_ts_1 = require("./shared/config-operations.js");
7
7
  async function run(args) {
8
8
  const options = {
9
9
  help: {
@@ -35,7 +35,7 @@ async function run(args) {
35
35
  '$ jbrowse add-track-json track.json --update',
36
36
  ];
37
37
  if (flags.help) {
38
- (0, utils_1.printHelp)({
38
+ (0, utils_ts_1.printHelp)({
39
39
  description,
40
40
  examples,
41
41
  usage: 'jbrowse add-track-json <track> [options]',
@@ -45,37 +45,32 @@ async function run(args) {
45
45
  }
46
46
  const track = positionals[0];
47
47
  if (!track) {
48
- console.error('Error: Missing required argument: track');
49
- console.error('Usage: jbrowse add-track-json <track> [options]');
50
- process.exit(1);
48
+ throw new Error('Missing required argument: track\nUsage: jbrowse add-track-json <track> [options]');
51
49
  }
52
- const output = flags.target || flags.out || '.';
53
- const isDir = (await fs_1.promises.lstat(output)).isDirectory();
54
- const target = isDir ? `${output}/config.json` : output;
55
- (0, utils_1.debug)(`Sequence location is: ${track}`);
50
+ const target = await (0, utils_ts_1.resolveConfigPath)(flags.target, flags.out);
51
+ (0, utils_ts_1.debug)(`Sequence location is: ${track}`);
56
52
  const { update } = flags;
57
- const config = await (0, utils_1.readJsonFile)(target);
58
- (0, utils_1.debug)(`Found existing config file ${target}`);
59
- const trackConfig = await (0, utils_1.readInlineOrFileJson)(track);
53
+ const config = await (0, utils_ts_1.readJsonFile)(target);
54
+ (0, utils_ts_1.debug)(`Found existing config file ${target}`);
55
+ const trackConfig = await (0, utils_ts_1.readInlineOrFileJson)(track);
60
56
  if (!config.tracks) {
61
57
  config.tracks = [];
62
58
  }
63
- const idx = config.tracks.findIndex(({ trackId }) => trackId === trackConfig.trackId);
64
- if (idx !== -1) {
65
- const existing = config.tracks[idx]?.name;
66
- (0, utils_1.debug)(`Found existing track ${existing} in configuration`);
67
- if (update) {
68
- (0, utils_1.debug)(`Overwriting track ${existing} in configuration`);
69
- config.tracks[idx] = trackConfig;
70
- }
71
- else {
72
- throw new Error(`Cannot add track ${trackConfig.name}, a track with that trackId already exists: ${existing}`);
73
- }
74
- }
75
- else {
76
- config.tracks.push(trackConfig);
77
- }
78
- (0, utils_1.debug)(`Writing configuration to file ${target}`);
79
- await (0, utils_1.writeJsonFile)(target, config);
80
- console.log(`${idx !== -1 ? 'Overwrote' : 'Added'} track "${trackConfig.name}" ${idx !== -1 ? 'in' : 'to'} ${target}`);
59
+ const { updatedItems, wasOverwritten } = (0, config_operations_ts_1.findAndUpdateOrAdd)({
60
+ items: config.tracks,
61
+ newItem: trackConfig,
62
+ idField: 'trackId',
63
+ getId: item => item.trackId,
64
+ allowOverwrite: update ?? false,
65
+ itemType: 'track',
66
+ });
67
+ config.tracks = updatedItems;
68
+ await (0, config_operations_ts_1.saveConfigAndReport)({
69
+ config,
70
+ target,
71
+ itemType: 'track',
72
+ itemName: trackConfig.name,
73
+ itemId: trackConfig.trackId,
74
+ wasOverwritten,
75
+ });
81
76
  }
@@ -8,7 +8,7 @@ exports.buildTrackConfig = buildTrackConfig;
8
8
  exports.addSyntenyAssemblyNames = addSyntenyAssemblyNames;
9
9
  const path_1 = __importDefault(require("path"));
10
10
  const json_parse_better_errors_1 = __importDefault(require("json-parse-better-errors"));
11
- const validators_1 = require("./validators");
11
+ const common_ts_1 = require("../../types/common.js");
12
12
  const SYNTENY_ADAPTERS = new Set([
13
13
  'PAFAdapter',
14
14
  'PairwiseIndexedPAFAdapter',
@@ -19,11 +19,11 @@ const SYNTENY_ADAPTERS = new Set([
19
19
  'MCScanSimpleAnchorsAdapter',
20
20
  ]);
21
21
  function mapLocationForFiles(p, load, subDir) {
22
- return !p || (0, validators_1.isUrl)(p) || load === 'inPlace'
22
+ return !p || (0, common_ts_1.isURL)(p) || load === 'inPlace'
23
23
  ? p
24
24
  : path_1.default.join(subDir || '', path_1.default.basename(p));
25
25
  }
26
- function buildTrackConfig({ location, trackType, trackId, name, assemblyNames, category, description, config, adapter, configContents, skipCheck, }) {
26
+ function buildTrackConfig({ location, trackType, trackId, name, assemblyNames, category, description, config, adapter, configContents, }) {
27
27
  const configObj = config ? (0, json_parse_better_errors_1.default)(config) : {};
28
28
  const finalTrackId = trackId || path_1.default.basename(location, path_1.default.extname(location));
29
29
  const finalName = name || finalTrackId;
@@ -38,18 +38,6 @@ function buildTrackConfig({ location, trackType, trackId, name, assemblyNames, c
38
38
  description,
39
39
  ...configObj,
40
40
  };
41
- // Special handling for AlignmentsTrack
42
- if (trackType === 'AlignmentsTrack') {
43
- const assembly = configContents.assemblies?.find(asm => asm.name === finalAssemblyNames);
44
- if (assembly) {
45
- // @ts-expect-error
46
- trackConfig.adapter.sequenceAdapter = assembly.sequence.adapter;
47
- }
48
- else if (!skipCheck) {
49
- console.error(`Error: Failed to find assemblyName ${finalAssemblyNames}`);
50
- process.exit(1);
51
- }
52
- }
53
41
  return trackConfig;
54
42
  }
55
43
  function addSyntenyAssemblyNames(adapter, assemblyNames) {
@@ -3,7 +3,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.isUrl = void 0;
7
6
  exports.validateLoadOption = validateLoadOption;
8
7
  exports.validateTrackArg = validateTrackArg;
9
8
  exports.validateLoadAndLocation = validateLoadAndLocation;
@@ -13,8 +12,7 @@ exports.validateTrackId = validateTrackId;
13
12
  exports.createTargetDirectory = createTargetDirectory;
14
13
  const fs_1 = __importDefault(require("fs"));
15
14
  const path_1 = __importDefault(require("path"));
16
- const isUrl = (loc) => loc?.match(/^https?:\/\//);
17
- exports.isUrl = isUrl;
15
+ const common_ts_1 = require("../../types/common.js");
18
16
  function validateLoadOption(load) {
19
17
  if (load && !['copy', 'symlink', 'move', 'inPlace'].includes(load)) {
20
18
  throw new Error('Error: --load must be one of: copy, symlink, move, inPlace');
@@ -22,17 +20,14 @@ function validateLoadOption(load) {
22
20
  }
23
21
  function validateTrackArg(track) {
24
22
  if (!track) {
25
- console.error('Missing 1 required arg:');
26
- console.error('track Track file or URL');
27
- console.error('See more help with --help');
28
- process.exit(1);
23
+ throw new Error('Missing 1 required arg:\ntrack Track file or URL\nSee more help with --help');
29
24
  }
30
25
  }
31
26
  function validateLoadAndLocation(location, load) {
32
- if (isUrl(location) && load) {
27
+ if ((0, common_ts_1.isURL)(location) && load) {
33
28
  throw new Error('The --load flag is used for local files only, but a URL was provided');
34
29
  }
35
- else if (!isUrl(location) && !load) {
30
+ else if (!(0, common_ts_1.isURL)(location) && !load) {
36
31
  throw new Error(`The --load flag should be used if a local file is used, example --load
37
32
  copy to copy the file into the config directory. Options for load are
38
33
  copy/move/symlink/inPlace (inPlace for no file operations)`);