@jbrowse/cli 3.6.0 → 3.6.1
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/bin/run +1 -1
- package/dist/base.js +5 -0
- package/dist/bin.js +3 -0
- package/dist/commands/add-assembly.js +143 -0
- package/dist/commands/add-connection.js +177 -0
- package/dist/commands/add-track-json.js +81 -0
- package/dist/commands/add-track-utils/adapter-utils.js +304 -0
- package/dist/commands/add-track-utils/file-operations.js +36 -0
- package/dist/commands/add-track-utils/track-config.js +63 -0
- package/dist/commands/add-track-utils/validators.js +74 -0
- package/dist/commands/add-track.js +193 -0
- package/dist/commands/admin-server-utils.js +238 -0
- package/dist/commands/admin-server.js +51 -0
- package/dist/commands/assembly-utils.js +410 -0
- package/dist/commands/create.js +121 -0
- package/dist/commands/make-pif-utils/cigar-utils.js +29 -0
- package/dist/commands/make-pif-utils/file-utils.js +38 -0
- package/dist/commands/make-pif-utils/pif-generator.js +64 -0
- package/dist/commands/make-pif-utils/validators.js +22 -0
- package/dist/commands/make-pif.js +58 -0
- package/dist/commands/remove-track.js +58 -0
- package/dist/commands/set-default-session.js +104 -0
- package/dist/commands/sort-bed-utils/constants.js +12 -0
- package/dist/commands/sort-bed-utils/process-utils.js +23 -0
- package/dist/commands/sort-bed-utils/sort-utils.js +24 -0
- package/dist/commands/sort-bed-utils/validators.js +22 -0
- package/dist/commands/sort-bed.js +49 -0
- package/dist/commands/sort-gff-utils/constants.js +13 -0
- package/dist/commands/sort-gff-utils/process-utils.js +23 -0
- package/dist/commands/sort-gff-utils/sort-utils.js +55 -0
- package/dist/commands/sort-gff-utils/validators.js +21 -0
- package/dist/commands/sort-gff.js +49 -0
- package/dist/commands/text-index-utils/adapter-utils.js +63 -0
- package/dist/commands/text-index-utils/aggregate.js +87 -0
- package/dist/commands/text-index-utils/config-utils.js +59 -0
- package/dist/commands/text-index-utils/file-list.js +31 -0
- package/dist/commands/text-index-utils/index.js +9 -0
- package/dist/commands/text-index-utils/indexing-utils.js +84 -0
- package/dist/commands/text-index-utils/per-track.js +65 -0
- package/dist/commands/text-index-utils/validators.js +20 -0
- package/dist/commands/text-index.js +113 -0
- package/dist/commands/track-utils.js +85 -0
- package/dist/commands/upgrade.js +122 -0
- package/dist/fetchWithProxy.js +12 -0
- package/dist/index.js +119 -0
- package/dist/types/common.js +128 -0
- package/dist/types/gff3Adapter.js +73 -0
- package/dist/types/vcfAdapter.js +76 -0
- package/dist/util.js +35 -0
- package/dist/utils.js +154 -0
- package/package.json +3 -3
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.resolveTrackConfigPath = resolveTrackConfigPath;
|
|
7
|
+
exports.loadTrackConfig = loadTrackConfig;
|
|
8
|
+
exports.processTrackFiles = processTrackFiles;
|
|
9
|
+
exports.addTrackToConfig = addTrackToConfig;
|
|
10
|
+
exports.saveTrackConfigAndReport = saveTrackConfigAndReport;
|
|
11
|
+
exports.buildTrackParams = buildTrackParams;
|
|
12
|
+
exports.createTrackConfiguration = createTrackConfiguration;
|
|
13
|
+
const fs_1 = __importDefault(require("fs"));
|
|
14
|
+
const path_1 = __importDefault(require("path"));
|
|
15
|
+
const utils_1 = require("../utils");
|
|
16
|
+
const adapter_utils_1 = require("./add-track-utils/adapter-utils");
|
|
17
|
+
const file_operations_1 = require("./add-track-utils/file-operations");
|
|
18
|
+
const track_config_1 = require("./add-track-utils/track-config");
|
|
19
|
+
const validators_1 = require("./add-track-utils/validators");
|
|
20
|
+
function resolveTrackConfigPath(output) {
|
|
21
|
+
const isDir = fs_1.default.lstatSync(output).isDirectory();
|
|
22
|
+
return isDir ? `${output}/config.json` : output;
|
|
23
|
+
}
|
|
24
|
+
async function loadTrackConfig(targetConfigPath) {
|
|
25
|
+
return await (0, utils_1.readJsonFile)(targetConfigPath);
|
|
26
|
+
}
|
|
27
|
+
async function processTrackFiles({ location, index, bed1, bed2, load, configDir, subDir, force, }) {
|
|
28
|
+
if (load) {
|
|
29
|
+
await Promise.all(Object.values((0, adapter_utils_1.guessFileNames)({ location, index, bed1, bed2 }))
|
|
30
|
+
.filter(f => !!f)
|
|
31
|
+
.map(src => (0, file_operations_1.loadFile)({
|
|
32
|
+
src,
|
|
33
|
+
destDir: configDir,
|
|
34
|
+
mode: load,
|
|
35
|
+
subDir,
|
|
36
|
+
force,
|
|
37
|
+
})));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function addTrackToConfig({ configContents, trackConfig, trackId, force, overwrite, }) {
|
|
41
|
+
const idx = (0, validators_1.validateTrackId)(configContents, trackId, force, overwrite);
|
|
42
|
+
const updatedConfig = { ...configContents };
|
|
43
|
+
if (idx !== -1) {
|
|
44
|
+
(0, utils_1.debug)(`Found existing trackId ${trackId} in configuration`);
|
|
45
|
+
(0, utils_1.debug)(`Overwriting track ${trackId} in configuration`);
|
|
46
|
+
updatedConfig.tracks[idx] = trackConfig;
|
|
47
|
+
return { updatedConfig, wasOverwritten: true };
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
updatedConfig.tracks.push(trackConfig);
|
|
51
|
+
return { updatedConfig, wasOverwritten: false };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async function saveTrackConfigAndReport({ config, targetConfigPath, name, trackId, wasOverwritten, }) {
|
|
55
|
+
(0, utils_1.debug)(`Writing configuration to file ${targetConfigPath}`);
|
|
56
|
+
await (0, utils_1.writeJsonFile)(targetConfigPath, config);
|
|
57
|
+
console.log(`${wasOverwritten ? 'Overwrote' : 'Added'} track with name "${name}" and trackId "${trackId}" ${wasOverwritten ? 'in' : 'to'} ${targetConfigPath}`);
|
|
58
|
+
}
|
|
59
|
+
function buildTrackParams({ flags, location, adapter, configContents, }) {
|
|
60
|
+
const trackType = flags.trackType || (0, adapter_utils_1.guessTrackType)(adapter.type);
|
|
61
|
+
const trackId = flags.trackId || path_1.default.basename(location, path_1.default.extname(location));
|
|
62
|
+
const name = flags.name || trackId;
|
|
63
|
+
const assemblyNames = flags.assemblyNames || configContents.assemblies?.[0]?.name || '';
|
|
64
|
+
return {
|
|
65
|
+
trackType,
|
|
66
|
+
trackId,
|
|
67
|
+
name,
|
|
68
|
+
assemblyNames,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function createTrackConfiguration({ location, trackParams, flags, adapter, configContents, skipCheck, }) {
|
|
72
|
+
return (0, track_config_1.buildTrackConfig)({
|
|
73
|
+
location,
|
|
74
|
+
trackType: trackParams.trackType,
|
|
75
|
+
trackId: trackParams.trackId,
|
|
76
|
+
name: trackParams.name,
|
|
77
|
+
assemblyNames: trackParams.assemblyNames,
|
|
78
|
+
category: flags.category,
|
|
79
|
+
description: flags.description,
|
|
80
|
+
config: flags.config,
|
|
81
|
+
adapter,
|
|
82
|
+
configContents,
|
|
83
|
+
skipCheck,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.run = run;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const util_1 = require("util");
|
|
10
|
+
const decompress_1 = __importDefault(require("decompress"));
|
|
11
|
+
const fetchWithProxy_1 = __importDefault(require("../fetchWithProxy"));
|
|
12
|
+
const utils_1 = require("../utils");
|
|
13
|
+
const description = 'Upgrades JBrowse 2 to latest version';
|
|
14
|
+
const examples = [
|
|
15
|
+
'# Upgrades current directory to latest jbrowse release',
|
|
16
|
+
'$ jbrowse upgrade',
|
|
17
|
+
'',
|
|
18
|
+
'# Upgrade jbrowse instance at a specific filesystem path',
|
|
19
|
+
'$ jbrowse upgrade /path/to/jbrowse2/installation',
|
|
20
|
+
'',
|
|
21
|
+
'# Upgrade to a specific tag',
|
|
22
|
+
'$ jbrowse upgrade /path/to/jbrowse2/installation --tag v1.0.0',
|
|
23
|
+
'',
|
|
24
|
+
'# List versions available on github',
|
|
25
|
+
'$ jbrowse upgrade --listVersions',
|
|
26
|
+
'',
|
|
27
|
+
'# Upgrade from a specific URL',
|
|
28
|
+
'$ jbrowse upgrade --url https://sample.com/jbrowse2.zip',
|
|
29
|
+
'',
|
|
30
|
+
'# Get nightly release from main branch',
|
|
31
|
+
'$ jbrowse upgrade --nightly',
|
|
32
|
+
];
|
|
33
|
+
const options = {
|
|
34
|
+
help: {
|
|
35
|
+
type: 'boolean',
|
|
36
|
+
short: 'h',
|
|
37
|
+
description: 'Display help for command',
|
|
38
|
+
},
|
|
39
|
+
// will need to account for pagination once there is a lot of releases
|
|
40
|
+
listVersions: {
|
|
41
|
+
type: 'boolean',
|
|
42
|
+
short: 'l',
|
|
43
|
+
description: 'Lists out all versions of JBrowse 2',
|
|
44
|
+
},
|
|
45
|
+
tag: {
|
|
46
|
+
type: 'string',
|
|
47
|
+
short: 't',
|
|
48
|
+
description: 'Version of JBrowse 2 to install. Format is v1.0.0.\nDefaults to latest',
|
|
49
|
+
},
|
|
50
|
+
branch: {
|
|
51
|
+
type: 'string',
|
|
52
|
+
description: 'Download a development build from a named git branch',
|
|
53
|
+
},
|
|
54
|
+
nightly: {
|
|
55
|
+
type: 'boolean',
|
|
56
|
+
description: 'Download the latest development build from the main branch',
|
|
57
|
+
},
|
|
58
|
+
clean: {
|
|
59
|
+
type: 'boolean',
|
|
60
|
+
description: 'Removes old js,map,and LICENSE files in the installation',
|
|
61
|
+
},
|
|
62
|
+
url: {
|
|
63
|
+
type: 'string',
|
|
64
|
+
short: 'u',
|
|
65
|
+
description: 'A direct URL to a JBrowse 2 release',
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
async function run(args) {
|
|
69
|
+
const { positionals, values: runFlags } = (0, util_1.parseArgs)({
|
|
70
|
+
options,
|
|
71
|
+
args,
|
|
72
|
+
allowPositionals: true,
|
|
73
|
+
});
|
|
74
|
+
const argsPath = positionals[0];
|
|
75
|
+
const { clean, listVersions, tag, url, branch, nightly } = runFlags;
|
|
76
|
+
if (runFlags.help) {
|
|
77
|
+
(0, utils_1.printHelp)({
|
|
78
|
+
options,
|
|
79
|
+
examples,
|
|
80
|
+
usage: 'jbrowse upgrade [localPath] [options]',
|
|
81
|
+
description,
|
|
82
|
+
});
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (listVersions) {
|
|
86
|
+
const versions = (await (0, utils_1.fetchGithubVersions)()).map(v => v.tag_name);
|
|
87
|
+
console.log(`All JBrowse versions:\n${versions.join('\n')}`);
|
|
88
|
+
process.exit(0);
|
|
89
|
+
}
|
|
90
|
+
if (!argsPath) {
|
|
91
|
+
throw new Error('No directory supplied');
|
|
92
|
+
}
|
|
93
|
+
if (!fs_1.default.existsSync(path_1.default.join(argsPath, 'manifest.json'))) {
|
|
94
|
+
throw new Error(`No manifest.json found in this directory, are you sure it is an
|
|
95
|
+
existing jbrowse 2 installation?`);
|
|
96
|
+
}
|
|
97
|
+
const locationUrl = url ||
|
|
98
|
+
(nightly ? await (0, utils_1.getBranch)('main') : '') ||
|
|
99
|
+
(branch ? await (0, utils_1.getBranch)(branch) : '') ||
|
|
100
|
+
(tag ? await (0, utils_1.getTag)(tag) : await (0, utils_1.getLatest)());
|
|
101
|
+
console.log(`Fetching ${locationUrl}...`);
|
|
102
|
+
const response = await (0, fetchWithProxy_1.default)(locationUrl);
|
|
103
|
+
if (!response.ok) {
|
|
104
|
+
throw new Error(`HTTP ${response.status} fetching ${locationUrl}: ${response.statusText}`);
|
|
105
|
+
}
|
|
106
|
+
const type = response.headers.get('content-type');
|
|
107
|
+
if (url &&
|
|
108
|
+
type !== 'application/zip' &&
|
|
109
|
+
type !== 'application/octet-stream') {
|
|
110
|
+
throw new Error('The URL provided does not seem to be a JBrowse installation URL');
|
|
111
|
+
}
|
|
112
|
+
if (clean) {
|
|
113
|
+
fs_1.default.rmSync(path_1.default.join(argsPath, 'static'), { recursive: true, force: true });
|
|
114
|
+
for (const f of fs_1.default
|
|
115
|
+
.readdirSync(argsPath)
|
|
116
|
+
.filter(f => f.includes('worker.js'))) {
|
|
117
|
+
fs_1.default.unlinkSync(path_1.default.join(argsPath, f));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
await (0, decompress_1.default)(Buffer.from(await response.arrayBuffer()), argsPath);
|
|
121
|
+
console.log(`Unpacked ${locationUrl} at ${argsPath}`);
|
|
122
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = fetchWithProxy;
|
|
4
|
+
const node_1 = require("node-fetch-native/node");
|
|
5
|
+
const proxy_1 = require("node-fetch-native/proxy");
|
|
6
|
+
const proxy = (0, proxy_1.createProxy)();
|
|
7
|
+
// The correct proxy `Agent` implementation to use will be determined
|
|
8
|
+
// via the `http_proxy` / `https_proxy` / `no_proxy` / etc. env vars
|
|
9
|
+
// https://github.com/unjs/node-fetch-native?tab=readme-ov-file#proxy-support
|
|
10
|
+
function fetchWithProxy(url, options = {}) {
|
|
11
|
+
return (0, node_1.fetch)(url, { ...options, ...proxy });
|
|
12
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.main = main;
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const util_1 = require("util");
|
|
11
|
+
// Command imports
|
|
12
|
+
const add_assembly_1 = require("./commands/add-assembly");
|
|
13
|
+
const add_connection_1 = require("./commands/add-connection");
|
|
14
|
+
const add_track_1 = require("./commands/add-track");
|
|
15
|
+
const add_track_json_1 = require("./commands/add-track-json");
|
|
16
|
+
const admin_server_1 = require("./commands/admin-server");
|
|
17
|
+
const create_1 = require("./commands/create");
|
|
18
|
+
const make_pif_1 = require("./commands/make-pif");
|
|
19
|
+
const remove_track_1 = require("./commands/remove-track");
|
|
20
|
+
const set_default_session_1 = require("./commands/set-default-session");
|
|
21
|
+
const sort_bed_1 = require("./commands/sort-bed");
|
|
22
|
+
const sort_gff_1 = require("./commands/sort-gff");
|
|
23
|
+
const text_index_1 = require("./commands/text-index");
|
|
24
|
+
const upgrade_1 = require("./commands/upgrade");
|
|
25
|
+
const commands = {
|
|
26
|
+
create: create_1.run,
|
|
27
|
+
'add-assembly': add_assembly_1.run,
|
|
28
|
+
'add-track': add_track_1.run,
|
|
29
|
+
'text-index': text_index_1.run,
|
|
30
|
+
'admin-server': admin_server_1.run,
|
|
31
|
+
upgrade: upgrade_1.run,
|
|
32
|
+
'make-pif': make_pif_1.run,
|
|
33
|
+
'sort-gff': sort_gff_1.run,
|
|
34
|
+
'sort-bed': sort_bed_1.run,
|
|
35
|
+
'add-connection': add_connection_1.run,
|
|
36
|
+
'add-track-json': add_track_json_1.run,
|
|
37
|
+
'remove-track': remove_track_1.run,
|
|
38
|
+
'set-default-session': set_default_session_1.run,
|
|
39
|
+
};
|
|
40
|
+
async function main(args) {
|
|
41
|
+
try {
|
|
42
|
+
const { values: flags, positionals } = (0, util_1.parseArgs)({
|
|
43
|
+
args,
|
|
44
|
+
options: {
|
|
45
|
+
help: {
|
|
46
|
+
type: 'boolean',
|
|
47
|
+
short: 'h',
|
|
48
|
+
default: false,
|
|
49
|
+
},
|
|
50
|
+
version: {
|
|
51
|
+
type: 'boolean',
|
|
52
|
+
short: 'v',
|
|
53
|
+
default: false,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
allowPositionals: true,
|
|
57
|
+
strict: false, // Allow unknown flags to be passed to subcommands
|
|
58
|
+
});
|
|
59
|
+
// Check if help or version is requested at the global level
|
|
60
|
+
if (flags.help && positionals.length === 0) {
|
|
61
|
+
showGlobalHelp();
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (flags.version && positionals.length === 0) {
|
|
65
|
+
const packageJson = JSON.parse(fs_1.default.readFileSync(path_1.default.join(__dirname, '../package.json'), 'utf8'));
|
|
66
|
+
console.log(`@jbrowse/cli version ${packageJson.version}`);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const commandName = positionals[0];
|
|
70
|
+
if (!commandName) {
|
|
71
|
+
console.error('Error: Missing command');
|
|
72
|
+
showGlobalHelp();
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
const command = commands[commandName];
|
|
76
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
77
|
+
if (!command) {
|
|
78
|
+
console.error(`Error: Unknown command "${commandName}"`);
|
|
79
|
+
console.error(`Available commands: ${Object.keys(commands).join(', ')}`);
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
// Pass the remaining arguments to the command
|
|
83
|
+
const commandArgs = args.slice(1); // Remove the command name from args
|
|
84
|
+
await command(commandArgs);
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
console.error('Error:', error instanceof Error ? error.message : error);
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function showGlobalHelp() {
|
|
92
|
+
console.log(`
|
|
93
|
+
JBrowse CLI
|
|
94
|
+
|
|
95
|
+
USAGE
|
|
96
|
+
$ jbrowse <command> [options]
|
|
97
|
+
|
|
98
|
+
COMMANDS
|
|
99
|
+
create Downloads and installs the latest JBrowse 2 release
|
|
100
|
+
add-assembly Add an assembly to a JBrowse 2 configuration
|
|
101
|
+
add-track Add a track to a JBrowse 2 configuration
|
|
102
|
+
text-index Make a text-indexing file for any given track(s)
|
|
103
|
+
admin-server Start up a small admin server for JBrowse configuration
|
|
104
|
+
upgrade Upgrades JBrowse 2 to latest version
|
|
105
|
+
make-pif Creates pairwise indexed PAF (PIF), with bgzip and tabix
|
|
106
|
+
sort-gff Helper utility to sort GFF files for tabix
|
|
107
|
+
sort-bed Helper utility to sort BED files for tabix
|
|
108
|
+
add-connection Add a connection to a JBrowse 2 configuration
|
|
109
|
+
add-track-json Add a track configuration directly from a JSON hunk
|
|
110
|
+
remove-track Remove a track configuration from a JBrowse 2 configuration
|
|
111
|
+
set-default-session Set a default session with views and tracks
|
|
112
|
+
|
|
113
|
+
OPTIONS
|
|
114
|
+
-h, --help Show help
|
|
115
|
+
-v, --version Show version
|
|
116
|
+
|
|
117
|
+
Use "jbrowse <command> --help" for more information about a command.
|
|
118
|
+
`);
|
|
119
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createRemoteStream = createRemoteStream;
|
|
7
|
+
exports.isURL = isURL;
|
|
8
|
+
exports.guessAdapterFromFileName = guessAdapterFromFileName;
|
|
9
|
+
exports.supported = supported;
|
|
10
|
+
exports.generateMeta = generateMeta;
|
|
11
|
+
const fs_1 = __importDefault(require("fs"));
|
|
12
|
+
const path_1 = __importDefault(require("path"));
|
|
13
|
+
const fetchWithProxy_1 = __importDefault(require("../fetchWithProxy"));
|
|
14
|
+
async function createRemoteStream(urlIn) {
|
|
15
|
+
const res = await (0, fetchWithProxy_1.default)(urlIn);
|
|
16
|
+
if (!res.ok) {
|
|
17
|
+
throw new Error(`Failed to fetch ${urlIn} status ${res.status} ${await res.text()}`);
|
|
18
|
+
}
|
|
19
|
+
return res;
|
|
20
|
+
}
|
|
21
|
+
function isURL(FileName) {
|
|
22
|
+
let url;
|
|
23
|
+
try {
|
|
24
|
+
url = new URL(FileName);
|
|
25
|
+
}
|
|
26
|
+
catch (_) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
return url.protocol === 'http:' || url.protocol === 'https:';
|
|
30
|
+
}
|
|
31
|
+
function makeLocation(location, protocol) {
|
|
32
|
+
if (protocol === 'uri') {
|
|
33
|
+
return {
|
|
34
|
+
uri: location,
|
|
35
|
+
locationType: 'UriLocation',
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
if (protocol === 'localPath') {
|
|
39
|
+
return {
|
|
40
|
+
localPath: path_1.default.resolve(location),
|
|
41
|
+
locationType: 'LocalPathLocation',
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
throw new Error(`invalid protocol ${protocol}`);
|
|
45
|
+
}
|
|
46
|
+
function guessAdapterFromFileName(filePath) {
|
|
47
|
+
const protocol = isURL(filePath) ? 'uri' : 'localPath';
|
|
48
|
+
const name = path_1.default.basename(filePath);
|
|
49
|
+
if (/\.vcf\.b?gz$/i.test(filePath)) {
|
|
50
|
+
return {
|
|
51
|
+
trackId: name,
|
|
52
|
+
name: name,
|
|
53
|
+
assemblyNames: [],
|
|
54
|
+
adapter: {
|
|
55
|
+
type: 'VcfTabixAdapter',
|
|
56
|
+
vcfGzLocation: makeLocation(filePath, protocol),
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
else if (/\.gff3?\.b?gz$/i.test(filePath)) {
|
|
61
|
+
return {
|
|
62
|
+
trackId: name,
|
|
63
|
+
name,
|
|
64
|
+
assemblyNames: [],
|
|
65
|
+
adapter: {
|
|
66
|
+
type: 'Gff3TabixAdapter',
|
|
67
|
+
gffGzLocation: makeLocation(filePath, protocol),
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
else if (/\.gtf?$/i.test(filePath)) {
|
|
72
|
+
return {
|
|
73
|
+
trackId: name,
|
|
74
|
+
name,
|
|
75
|
+
assemblyNames: [],
|
|
76
|
+
adapter: {
|
|
77
|
+
type: 'GtfAdapter',
|
|
78
|
+
gtfLocation: { uri: filePath, locationType: 'UriLocation' },
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
else if (/\.vcf$/i.test(filePath)) {
|
|
83
|
+
return {
|
|
84
|
+
trackId: name,
|
|
85
|
+
name,
|
|
86
|
+
assemblyNames: [],
|
|
87
|
+
adapter: {
|
|
88
|
+
type: 'VcfAdapter',
|
|
89
|
+
vcfLocation: makeLocation(filePath, protocol),
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
else if (/\.gff3?$/i.test(filePath)) {
|
|
94
|
+
return {
|
|
95
|
+
trackId: name,
|
|
96
|
+
name,
|
|
97
|
+
assemblyNames: [],
|
|
98
|
+
adapter: {
|
|
99
|
+
type: 'Gff3Adapter',
|
|
100
|
+
gffLocation: makeLocation(filePath, protocol),
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
throw new Error(`Unsupported file type ${filePath}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function supported(type = '') {
|
|
109
|
+
return [
|
|
110
|
+
'Gff3TabixAdapter',
|
|
111
|
+
'VcfTabixAdapter',
|
|
112
|
+
'Gff3Adapter',
|
|
113
|
+
'VcfAdapter',
|
|
114
|
+
].includes(type);
|
|
115
|
+
}
|
|
116
|
+
async function generateMeta({ trackConfigs, attributes, outLocation, name, typesToExclude, assemblyNames, }) {
|
|
117
|
+
const tracks = trackConfigs.map(({ adapter, textSearching, trackId }) => ({
|
|
118
|
+
trackId,
|
|
119
|
+
attributesIndexed: textSearching?.indexingAttributes || attributes,
|
|
120
|
+
excludedTypes: textSearching?.indexingFeatureTypesToExclude || typesToExclude,
|
|
121
|
+
adapterConf: adapter,
|
|
122
|
+
}));
|
|
123
|
+
fs_1.default.writeFileSync(path_1.default.join(outLocation, 'trix', `${name}_meta.json`), JSON.stringify({
|
|
124
|
+
dateCreated: new Date().toISOString(),
|
|
125
|
+
tracks,
|
|
126
|
+
assemblyNames,
|
|
127
|
+
}, null, 2));
|
|
128
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.indexGff3 = indexGff3;
|
|
7
|
+
const readline_1 = __importDefault(require("readline"));
|
|
8
|
+
const zlib_1 = require("zlib");
|
|
9
|
+
const cli_progress_1 = require("cli-progress");
|
|
10
|
+
const util_1 = require("../util");
|
|
11
|
+
async function* indexGff3({ config, attributesToIndex, inLocation, outLocation, typesToExclude, quiet, }) {
|
|
12
|
+
const { trackId } = config;
|
|
13
|
+
// progress bar code was aided by blog post at
|
|
14
|
+
// https://webomnizz.com/download-a-file-with-progressbar-using-node-js/
|
|
15
|
+
const progressBar = new cli_progress_1.SingleBar({
|
|
16
|
+
format: `{bar} ${trackId} {percentage}% | ETA: {eta}s`,
|
|
17
|
+
etaBuffer: 2000,
|
|
18
|
+
}, cli_progress_1.Presets.shades_classic);
|
|
19
|
+
let receivedBytes = 0;
|
|
20
|
+
const { totalBytes, stream } = await (0, util_1.getLocalOrRemoteStream)(inLocation, outLocation);
|
|
21
|
+
if (!quiet) {
|
|
22
|
+
progressBar.start(totalBytes, 0);
|
|
23
|
+
}
|
|
24
|
+
// @ts-expect-error
|
|
25
|
+
stream.on('data', chunk => {
|
|
26
|
+
receivedBytes += chunk.length;
|
|
27
|
+
progressBar.update(receivedBytes);
|
|
28
|
+
});
|
|
29
|
+
const rl = readline_1.default.createInterface({
|
|
30
|
+
// @ts-expect-error
|
|
31
|
+
input: /.b?gz$/.exec(inLocation) ? stream.pipe((0, zlib_1.createGunzip)()) : stream,
|
|
32
|
+
});
|
|
33
|
+
for await (const line of rl) {
|
|
34
|
+
if (!line.trim()) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
else if (line.startsWith('#')) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
else if (line.startsWith('>')) {
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
const [seq_id, , type, start, end, , , , col9] = line.split('\t');
|
|
44
|
+
const locStr = `${seq_id}:${start}..${end}`;
|
|
45
|
+
if (!typesToExclude.includes(type)) {
|
|
46
|
+
// turns gff3 attrs into a map, and converts the arrays into space
|
|
47
|
+
// separated strings
|
|
48
|
+
const col9attrs = Object.fromEntries(col9
|
|
49
|
+
.split(';')
|
|
50
|
+
.map(f => f.trim())
|
|
51
|
+
.filter(f => !!f)
|
|
52
|
+
.map(f => f.split('='))
|
|
53
|
+
.map(([key, val]) => [
|
|
54
|
+
key.trim(),
|
|
55
|
+
val
|
|
56
|
+
? (0, util_1.decodeURIComponentNoThrow)(val).trim().split(',').join(' ')
|
|
57
|
+
: undefined,
|
|
58
|
+
]));
|
|
59
|
+
const attrs = attributesToIndex
|
|
60
|
+
.map(attr => col9attrs[attr])
|
|
61
|
+
.filter((f) => !!f);
|
|
62
|
+
if (attrs.length) {
|
|
63
|
+
const record = JSON.stringify([
|
|
64
|
+
encodeURIComponent(locStr),
|
|
65
|
+
encodeURIComponent(trackId),
|
|
66
|
+
...attrs.map(a => encodeURIComponent(a)),
|
|
67
|
+
]).replaceAll(',', '|');
|
|
68
|
+
yield `${record} ${[...new Set(attrs)].join(' ')}\n`;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
progressBar.stop();
|
|
73
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.indexVcf = indexVcf;
|
|
7
|
+
const readline_1 = __importDefault(require("readline"));
|
|
8
|
+
const zlib_1 = require("zlib");
|
|
9
|
+
const cli_progress_1 = require("cli-progress");
|
|
10
|
+
const util_1 = require("../util");
|
|
11
|
+
async function* indexVcf({ config, attributesToIndex, inLocation, outLocation, quiet, }) {
|
|
12
|
+
const { trackId } = config;
|
|
13
|
+
// progress bar code was aided by blog post at
|
|
14
|
+
// https://webomnizz.com/download-a-file-with-progressbar-using-node-js/
|
|
15
|
+
const progressBar = new cli_progress_1.SingleBar({
|
|
16
|
+
format: `{bar} ${trackId} {percentage}% | ETA: {eta}s`,
|
|
17
|
+
etaBuffer: 2000,
|
|
18
|
+
}, cli_progress_1.Presets.shades_classic);
|
|
19
|
+
let receivedBytes = 0;
|
|
20
|
+
const { totalBytes, stream } = await (0, util_1.getLocalOrRemoteStream)(inLocation, outLocation);
|
|
21
|
+
if (!quiet) {
|
|
22
|
+
progressBar.start(totalBytes, 0);
|
|
23
|
+
}
|
|
24
|
+
// @ts-expect-error
|
|
25
|
+
stream.on('data', chunk => {
|
|
26
|
+
receivedBytes += chunk.length;
|
|
27
|
+
progressBar.update(receivedBytes);
|
|
28
|
+
});
|
|
29
|
+
const gzStream = /.b?gz$/.exec(inLocation)
|
|
30
|
+
? // @ts-expect-error
|
|
31
|
+
stream.pipe((0, zlib_1.createGunzip)())
|
|
32
|
+
: stream;
|
|
33
|
+
const rl = readline_1.default.createInterface({
|
|
34
|
+
input: gzStream,
|
|
35
|
+
});
|
|
36
|
+
for await (const line of rl) {
|
|
37
|
+
if (line.startsWith('#')) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
41
|
+
const [ref, pos, id, _ref, _alt, _qual, _filter, info] = line.split('\t');
|
|
42
|
+
// turns gff3 attrs into a map, and converts the arrays into space
|
|
43
|
+
// separated strings
|
|
44
|
+
const fields = Object.fromEntries(info
|
|
45
|
+
.split(';')
|
|
46
|
+
.map(f => f.trim())
|
|
47
|
+
.filter(f => !!f)
|
|
48
|
+
.map(f => f.split('='))
|
|
49
|
+
.map(([key, val]) => [
|
|
50
|
+
key.trim(),
|
|
51
|
+
val
|
|
52
|
+
? (0, util_1.decodeURIComponentNoThrow)(val).trim().split(',').join(' ')
|
|
53
|
+
: undefined,
|
|
54
|
+
]));
|
|
55
|
+
const end = fields.END;
|
|
56
|
+
const locStr = `${ref}:${pos}..${end || +pos + 1}`;
|
|
57
|
+
if (id === '.') {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const infoAttrs = attributesToIndex
|
|
61
|
+
.map(attr => fields[attr])
|
|
62
|
+
.filter((f) => !!f);
|
|
63
|
+
const ids = id.split(',');
|
|
64
|
+
for (const id of ids) {
|
|
65
|
+
const attrs = [id];
|
|
66
|
+
const record = JSON.stringify([
|
|
67
|
+
encodeURIComponent(locStr),
|
|
68
|
+
encodeURIComponent(trackId),
|
|
69
|
+
encodeURIComponent(id || ''),
|
|
70
|
+
...infoAttrs.map(a => encodeURIComponent(a || '')),
|
|
71
|
+
]).replaceAll(',', '|');
|
|
72
|
+
yield `${record} ${[...new Set(attrs)].join(' ')}\n`;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
progressBar.stop();
|
|
76
|
+
}
|
package/dist/util.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getLocalOrRemoteStream = getLocalOrRemoteStream;
|
|
7
|
+
exports.decodeURIComponentNoThrow = decodeURIComponentNoThrow;
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const common_1 = require("./types/common");
|
|
11
|
+
async function getLocalOrRemoteStream(uri, out) {
|
|
12
|
+
if ((0, common_1.isURL)(uri)) {
|
|
13
|
+
const result = await (0, common_1.createRemoteStream)(uri);
|
|
14
|
+
return {
|
|
15
|
+
totalBytes: +(result.headers.get('Content-Length') || 0),
|
|
16
|
+
stream: result.body,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
const filename = path_1.default.isAbsolute(uri) ? uri : path_1.default.join(out, uri);
|
|
21
|
+
return {
|
|
22
|
+
totalBytes: fs_1.default.statSync(filename).size,
|
|
23
|
+
stream: fs_1.default.createReadStream(filename),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function decodeURIComponentNoThrow(uri) {
|
|
28
|
+
try {
|
|
29
|
+
return decodeURIComponent(uri);
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
// avoid throwing exception on a failure to decode URI component
|
|
33
|
+
return uri;
|
|
34
|
+
}
|
|
35
|
+
}
|