@jbrowse/cli 4.3.0 → 5.0.0-beta.2
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 +413 -57
- package/bin/run +1 -1
- package/bundle/index.js +550 -2659
- package/dist/base.js +0 -3
- package/dist/bin.js +2 -1
- package/dist/cliFetch.js +3 -0
- package/dist/commands/add-assembly/index.js +46 -19
- package/dist/commands/add-assembly/utils.js +204 -290
- package/dist/commands/add-connection.js +73 -79
- package/dist/commands/add-track-json.js +24 -12
- package/dist/commands/add-track-utils/adapter-utils.js +222 -288
- package/dist/commands/add-track-utils/file-operations.js +27 -11
- package/dist/commands/add-track-utils/multiwig.js +47 -0
- package/dist/commands/add-track-utils/track-config.js +68 -25
- package/dist/commands/add-track-utils/validators.js +36 -20
- package/dist/commands/add-track.js +201 -62
- package/dist/commands/admin-server/index.js +30 -49
- package/dist/commands/admin-server/utils.js +235 -125
- package/dist/commands/create.js +18 -34
- package/dist/commands/make-density/density-generator.js +180 -0
- package/dist/commands/make-density/index.js +139 -0
- package/dist/commands/make-pif/index.js +128 -11
- package/dist/commands/make-pif/pif-generator.js +249 -43
- package/dist/commands/process-utils.js +13 -2
- package/dist/commands/remove-track.js +20 -13
- package/dist/commands/set-default-session.js +35 -31
- package/dist/commands/shared/config-operations.js +3 -10
- package/dist/commands/shared/density.js +12 -0
- package/dist/commands/shared/sort-utils.js +67 -10
- package/dist/commands/shared/validators.js +38 -3
- package/dist/commands/sort-bed.js +2 -33
- package/dist/commands/sort-gff.js +2 -33
- package/dist/commands/text-index/adapter-utils.js +6 -23
- package/dist/commands/text-index/aggregate.js +40 -34
- package/dist/commands/text-index/command.js +35 -7
- package/dist/commands/text-index/config-utils.js +60 -83
- package/dist/commands/text-index/file-list.js +32 -18
- package/dist/commands/text-index/index.js +4 -4
- package/dist/commands/text-index/indexing-utils.js +49 -73
- package/dist/commands/text-index/per-track.js +44 -31
- package/dist/commands/text-index/validators.js +1 -1
- package/dist/commands/upgrade.js +20 -32
- package/dist/commands/validate/configManifest.generated.js +5765 -0
- package/dist/commands/validate/displayDefaultKeys.js +28 -0
- package/dist/commands/validate/index.js +97 -0
- package/dist/commands/validate/suggest.js +35 -0
- package/dist/commands/validate/types.js +6 -0
- package/dist/commands/validate/validateConfig.js +522 -0
- package/dist/index.js +104 -50
- package/dist/types/common.js +3 -27
- package/dist/utils.js +309 -128
- package/dist/version.js +1 -1
- package/package.json +8 -10
- package/dist/commands/make-pif/cigar-utils.js +0 -24
- package/dist/commands/make-pif/file-utils.js +0 -30
- package/dist/commands/track-utils.js +0 -74
- package/dist/util.js +0 -35
|
@@ -1,29 +1,26 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
async function resolveURL(location, check = true) {
|
|
7
|
-
let locationUrl;
|
|
1
|
+
import { parseArgs } from 'node:util';
|
|
2
|
+
import { debug, parseCommaSeparatedString, printHelp, readConfigFile, requirePositional, resolveConfigPath, } from '../utils.js';
|
|
3
|
+
import { parseConfigFlag } from './add-track-utils/validators.js';
|
|
4
|
+
import { findAndUpdateOrAdd, saveConfigAndReport, } from './shared/config-operations.js';
|
|
5
|
+
function resolveURL(location) {
|
|
8
6
|
try {
|
|
9
|
-
|
|
7
|
+
return new URL(location);
|
|
10
8
|
}
|
|
11
9
|
catch (error) {
|
|
12
|
-
throw new Error(`The location ${location} provided is not a valid URL
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const response = await fetch(`${locationUrl}`, { method: 'HEAD' });
|
|
16
|
-
if (!response.ok) {
|
|
17
|
-
throw new Error(`HTTP ${response.status} fetching ${locationUrl}`);
|
|
18
|
-
}
|
|
10
|
+
throw new Error(`The location ${location} provided is not a valid URL`, {
|
|
11
|
+
cause: error,
|
|
12
|
+
});
|
|
19
13
|
}
|
|
20
|
-
return locationUrl.href;
|
|
21
14
|
}
|
|
15
|
+
// a hub.txt filename and a jbrowse/data path are the two conventions we can
|
|
16
|
+
// recognize. Both are read off the URL's path rather than the whole href, so a
|
|
17
|
+
// query string can't fake one and a host that happens to be named hub.txt can't
|
|
18
|
+
// be mistaken for a hub file.
|
|
22
19
|
function determineConnectionType(url) {
|
|
23
|
-
if (
|
|
20
|
+
if (url.pathname.endsWith('/hub.txt')) {
|
|
24
21
|
return 'UCSCTrackHubConnection';
|
|
25
22
|
}
|
|
26
|
-
if (url.includes('jbrowse/data')) {
|
|
23
|
+
if (url.pathname.includes('jbrowse/data')) {
|
|
27
24
|
return 'JBrowse1Connection';
|
|
28
25
|
}
|
|
29
26
|
return 'custom';
|
|
@@ -66,18 +63,10 @@ export async function run(args) {
|
|
|
66
63
|
type: 'string',
|
|
67
64
|
description: 'Synonym for target',
|
|
68
65
|
},
|
|
69
|
-
skipCheck: {
|
|
70
|
-
type: 'boolean',
|
|
71
|
-
description: "Don't check whether the data directory URL exists",
|
|
72
|
-
},
|
|
73
|
-
overwrite: {
|
|
74
|
-
type: 'boolean',
|
|
75
|
-
description: 'Overwrites any existing connections if same connection id',
|
|
76
|
-
},
|
|
77
66
|
force: {
|
|
78
67
|
type: 'boolean',
|
|
79
68
|
short: 'f',
|
|
80
|
-
description: '
|
|
69
|
+
description: 'Overwrite existing connection if one with the same id exists',
|
|
81
70
|
},
|
|
82
71
|
};
|
|
83
72
|
const { values: flags, positionals } = parseArgs({
|
|
@@ -86,81 +75,86 @@ export async function run(args) {
|
|
|
86
75
|
allowPositionals: true,
|
|
87
76
|
});
|
|
88
77
|
const description = 'Add a connection to a JBrowse 2 configuration';
|
|
78
|
+
const usage = 'jbrowse add-connection <connectionUrlOrPath> [options]';
|
|
89
79
|
const examples = [
|
|
90
|
-
'
|
|
91
|
-
'$ jbrowse add-connection
|
|
92
|
-
'
|
|
93
|
-
'
|
|
94
|
-
|
|
80
|
+
'# add a JBrowse 1 data directory connection (type inferred from the jbrowse/data path)',
|
|
81
|
+
'$ jbrowse add-connection https://mysite.com/jbrowse/data/ -a hg19',
|
|
82
|
+
'',
|
|
83
|
+
'# force the JBrowse1Connection type for a non-standard data folder path',
|
|
84
|
+
'$ jbrowse add-connection https://mysite.com/jbrowse/custom_data_folder/ --type JBrowse1Connection -a hg38',
|
|
85
|
+
'',
|
|
86
|
+
'# add a UCSC track hub (type inferred from the hub.txt filename)',
|
|
87
|
+
'$ jbrowse add-connection https://mysite.com/path/to/hub.txt',
|
|
88
|
+
'',
|
|
89
|
+
'# force the UCSCTrackHubConnection type for a hub file not named hub.txt',
|
|
90
|
+
'$ jbrowse add-connection https://mysite.com/path/to/custom_hub_name.txt --type UCSCTrackHubConnection',
|
|
91
|
+
'',
|
|
92
|
+
'# add a custom connection type with extra config',
|
|
93
|
+
`$ jbrowse add-connection https://mysite.com/path/to/custom --type custom --config '{"uri":{"url":"https://mysite.com/path/to/custom"}, "locationType": "UriLocation"}' -a hg19`,
|
|
94
|
+
'',
|
|
95
|
+
'# set an explicit id/name and write to a specific config file',
|
|
95
96
|
'$ jbrowse add-connection https://mysite.com/path/to/hub.txt --connectionId newId --name newName --target /path/to/jb2/installation/config.json',
|
|
96
97
|
];
|
|
97
98
|
if (flags.help) {
|
|
98
99
|
printHelp({
|
|
99
100
|
description,
|
|
100
101
|
examples,
|
|
101
|
-
usage
|
|
102
|
+
usage,
|
|
102
103
|
options,
|
|
103
104
|
});
|
|
104
105
|
return;
|
|
105
106
|
}
|
|
106
107
|
const connectionUrlOrPath = positionals[0];
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
requirePositional(connectionUrlOrPath, 'connectionUrlOrPath', usage);
|
|
109
|
+
const { assemblyNames, type, name, config, connectionId, force } = flags;
|
|
110
|
+
const configObj = config ? parseConfigFlag(config) : undefined;
|
|
110
111
|
const target = await resolveConfigPath(flags.target, flags.out);
|
|
111
|
-
const
|
|
112
|
-
const
|
|
113
|
-
const configContents = await readJsonFile(target);
|
|
112
|
+
const url = resolveURL(connectionUrlOrPath);
|
|
113
|
+
const configContents = await readConfigFile(target);
|
|
114
114
|
debug(`Using config file ${target}`);
|
|
115
115
|
if (!configContents.assemblies?.length) {
|
|
116
116
|
throw new Error('No assemblies found. Please add one before adding connections');
|
|
117
117
|
}
|
|
118
118
|
const configType = type || determineConnectionType(url);
|
|
119
119
|
const id = connectionId ||
|
|
120
|
-
[configType, assemblyNames, Date.now()].filter(
|
|
120
|
+
[configType, assemblyNames, Date.now()].filter(Boolean).join('-');
|
|
121
|
+
// each known connection type stores the URL under its own location slot; a
|
|
122
|
+
// custom type carries no location, so its --config must supply one
|
|
123
|
+
const locationField = {
|
|
124
|
+
UCSCTrackHubConnection: 'hubTxtLocation',
|
|
125
|
+
JBrowse1Connection: 'dataDirLocation',
|
|
126
|
+
}[configType];
|
|
127
|
+
// a JBrowse 1 connection serves exactly one assembly, so it falls back to the
|
|
128
|
+
// config's first (the assemblies list is known non-empty by here)
|
|
129
|
+
const defaultAssemblyNames = configType === 'JBrowse1Connection'
|
|
130
|
+
? [configContents.assemblies[0].name]
|
|
131
|
+
: undefined;
|
|
121
132
|
const connectionConfig = {
|
|
122
133
|
type: configType,
|
|
123
134
|
name: name || id,
|
|
124
|
-
...(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
uri: url,
|
|
128
|
-
locationType: 'UriLocation',
|
|
129
|
-
},
|
|
130
|
-
}
|
|
131
|
-
: {}),
|
|
132
|
-
...(configType === 'JBrowse1Connection'
|
|
133
|
-
? {
|
|
134
|
-
dataDirLocation: {
|
|
135
|
-
uri: url,
|
|
136
|
-
locationType: 'UriLocation',
|
|
137
|
-
},
|
|
138
|
-
}
|
|
139
|
-
: {}),
|
|
135
|
+
...(locationField && {
|
|
136
|
+
[locationField]: { uri: url.href, locationType: 'UriLocation' },
|
|
137
|
+
}),
|
|
140
138
|
connectionId: id,
|
|
141
139
|
assemblyNames: assemblyNames
|
|
142
|
-
? assemblyNames
|
|
143
|
-
:
|
|
144
|
-
|
|
145
|
-
: undefined,
|
|
146
|
-
...(config ? parseJSON(config) : {}),
|
|
140
|
+
? parseCommaSeparatedString(assemblyNames)
|
|
141
|
+
: defaultAssemblyNames,
|
|
142
|
+
...configObj,
|
|
147
143
|
};
|
|
148
|
-
|
|
149
|
-
configContents.connections
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
await writeJsonFile(target, configContents);
|
|
165
|
-
console.log(`${idx !== -1 ? 'Overwrote' : 'Added'} connection "${name || id}" ${idx !== -1 ? 'in' : 'to'} ${target}`);
|
|
144
|
+
const { updatedItems: connections, wasOverwritten } = findAndUpdateOrAdd({
|
|
145
|
+
items: configContents.connections ?? [],
|
|
146
|
+
newItem: connectionConfig,
|
|
147
|
+
idField: 'connectionId',
|
|
148
|
+
getId: item => item.connectionId,
|
|
149
|
+
force: force ?? false,
|
|
150
|
+
itemType: 'connection',
|
|
151
|
+
});
|
|
152
|
+
await saveConfigAndReport({
|
|
153
|
+
config: { ...configContents, connections },
|
|
154
|
+
target,
|
|
155
|
+
itemType: 'connection',
|
|
156
|
+
itemName: name || id,
|
|
157
|
+
itemId: id,
|
|
158
|
+
wasOverwritten,
|
|
159
|
+
});
|
|
166
160
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { parseArgs } from 'util';
|
|
2
|
-
import { debug, printHelp, readInlineOrFileJson,
|
|
3
|
-
import { findAndUpdateOrAdd, saveConfigAndReport, } from
|
|
1
|
+
import { parseArgs } from 'node:util';
|
|
2
|
+
import { debug, printHelp, readInlineOrFileJson, readConfigFile, requirePositional, resolveConfigPath, } from '../utils.js';
|
|
3
|
+
import { findAndUpdateOrAdd, saveConfigAndReport, } from './shared/config-operations.js';
|
|
4
4
|
export async function run(args) {
|
|
5
5
|
const options = {
|
|
6
6
|
help: {
|
|
@@ -27,38 +27,50 @@ export async function run(args) {
|
|
|
27
27
|
allowPositionals: true,
|
|
28
28
|
});
|
|
29
29
|
const description = 'Add a track configuration directly from a JSON hunk to the JBrowse 2 configuration';
|
|
30
|
+
const usage = 'jbrowse add-track-json <track> [options]';
|
|
31
|
+
const notes = 'The track argument is a JSON file, inline JSON, or "-" to read the JSON ' +
|
|
32
|
+
'from stdin, so a track config can be generated and piped straight in.';
|
|
30
33
|
const examples = [
|
|
34
|
+
'# add a track from a JSON file',
|
|
31
35
|
'$ jbrowse add-track-json track.json',
|
|
36
|
+
'',
|
|
37
|
+
'# update an existing track (matched by trackId) with new JSON contents',
|
|
32
38
|
'$ jbrowse add-track-json track.json --update',
|
|
39
|
+
'',
|
|
40
|
+
'# pass the track config inline instead of via a file',
|
|
41
|
+
`$ jbrowse add-track-json '{"type":"FeatureTrack","trackId":"genes","assemblyNames":["hg38"],"adapter":{"type":"Gff3TabixAdapter","gffGzLocation":{"uri":"genes.gff.gz"}}}'`,
|
|
42
|
+
'',
|
|
43
|
+
'# pipe the track config in from another program',
|
|
44
|
+
`$ jq '.tracks[0]' other/config.json | jbrowse add-track-json -`,
|
|
45
|
+
'',
|
|
46
|
+
'# write to a config.json in a specific installation directory',
|
|
47
|
+
'$ jbrowse add-track-json track.json --out /path/to/jb2/',
|
|
33
48
|
];
|
|
34
49
|
if (flags.help) {
|
|
35
50
|
printHelp({
|
|
36
51
|
description,
|
|
37
52
|
examples,
|
|
38
|
-
|
|
53
|
+
notes,
|
|
54
|
+
usage,
|
|
39
55
|
options,
|
|
40
56
|
});
|
|
41
57
|
return;
|
|
42
58
|
}
|
|
43
59
|
const track = positionals[0];
|
|
44
|
-
|
|
45
|
-
throw new Error('Missing required argument: track\nUsage: jbrowse add-track-json <track> [options]');
|
|
46
|
-
}
|
|
60
|
+
requirePositional(track, 'track', usage);
|
|
47
61
|
const target = await resolveConfigPath(flags.target, flags.out);
|
|
48
62
|
debug(`Sequence location is: ${track}`);
|
|
49
63
|
const { update } = flags;
|
|
50
|
-
const config = await
|
|
64
|
+
const config = await readConfigFile(target);
|
|
51
65
|
debug(`Found existing config file ${target}`);
|
|
52
66
|
const trackConfig = await readInlineOrFileJson(track);
|
|
53
|
-
|
|
54
|
-
config.tracks = [];
|
|
55
|
-
}
|
|
67
|
+
config.tracks ??= [];
|
|
56
68
|
const { updatedItems, wasOverwritten } = findAndUpdateOrAdd({
|
|
57
69
|
items: config.tracks,
|
|
58
70
|
newItem: trackConfig,
|
|
59
71
|
idField: 'trackId',
|
|
60
72
|
getId: item => item.trackId,
|
|
61
|
-
|
|
73
|
+
force: update ?? false,
|
|
62
74
|
itemType: 'track',
|
|
63
75
|
});
|
|
64
76
|
config.tracks = updatedItems;
|