@jbrowse/text-indexing-core 5.0.0-beta.1 → 5.0.0-beta.10
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/esm/index.d.ts +4 -4
- package/esm/index.js +3 -3
- package/esm/indexFiles.d.ts +3 -5
- package/esm/indexFiles.js +8 -12
- package/esm/trixPaths.d.ts +2 -5
- package/esm/trixPaths.js +2 -5
- package/esm/types/common.d.ts +0 -9
- package/esm/types/common.js +0 -19
- package/esm/types/gff3Adapter.js +18 -8
- package/esm/types/gtfAdapter.js +2 -5
- package/esm/types/vcfAdapter.js +2 -8
- package/esm/util.d.ts +21 -0
- package/esm/util.js +22 -0
- package/esm/writeTrixIndex.d.ts +19 -0
- package/esm/writeTrixIndex.js +37 -0
- package/package.json +4 -2
package/esm/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export { decodeURIComponentNoThrow, defaultAttributesToIndex, defaultFeatureTypesToExclude, indexableAdapters, isSupportedIndexingAdapter, } from './util.ts';
|
|
2
|
-
export type { Gff3IndexerOptions, Gff3Adapter, Gff3TabixAdapter, GtfAdapter, IndexableFormat, IndexerOptions, LocalPathLocation, Track, UriLocation, VcfAdapter, VcfTabixAdapter, } from './util.ts';
|
|
3
|
-
export { createReadlineInterface,
|
|
1
|
+
export { decodeURIComponentNoThrow, defaultAttributesToIndex, defaultFeatureTypesToExclude, defaultIndexingPolicy, indexableAdapters, isSupportedIndexingAdapter, trackIndexingPolicy, } from './util.ts';
|
|
2
|
+
export type { Gff3IndexerOptions, Gff3Adapter, Gff3TabixAdapter, GtfAdapter, IndexableFormat, IndexerOptions, IndexingPolicy, LocalPathLocation, Track, UriLocation, VcfAdapter, VcfTabixAdapter, } from './util.ts';
|
|
3
|
+
export { createReadlineInterface, getLocalOrRemoteStream, guessAdapterFromFileName, isURL, makeLocation, parseAttributes, } from './types/common.ts';
|
|
4
4
|
export { TRIX_DIR, sanitizeForFilename, trixFileNames, trixFilePaths, trixFileUris, } from './trixPaths.ts';
|
|
5
5
|
export { indexGff3 } from './types/gff3Adapter.ts';
|
|
6
6
|
export { indexGtf } from './types/gtfAdapter.ts';
|
|
7
7
|
export { indexVcf } from './types/vcfAdapter.ts';
|
|
8
|
-
export { indexFiles } from './indexFiles.ts';
|
|
9
8
|
export type { TrackIndexProgress } from './indexFiles.ts';
|
|
9
|
+
export { writeTrixIndex } from './writeTrixIndex.ts';
|
package/esm/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { decodeURIComponentNoThrow, defaultAttributesToIndex, defaultFeatureTypesToExclude, indexableAdapters, isSupportedIndexingAdapter, } from './util.js';
|
|
2
|
-
export { createReadlineInterface,
|
|
1
|
+
export { decodeURIComponentNoThrow, defaultAttributesToIndex, defaultFeatureTypesToExclude, defaultIndexingPolicy, indexableAdapters, isSupportedIndexingAdapter, trackIndexingPolicy, } from './util.js';
|
|
2
|
+
export { createReadlineInterface, getLocalOrRemoteStream, guessAdapterFromFileName, isURL, makeLocation, parseAttributes, } from './types/common.js';
|
|
3
3
|
export { TRIX_DIR, sanitizeForFilename, trixFileNames, trixFilePaths, trixFileUris, } from './trixPaths.js';
|
|
4
4
|
export { indexGff3 } from './types/gff3Adapter.js';
|
|
5
5
|
export { indexGtf } from './types/gtfAdapter.js';
|
|
6
6
|
export { indexVcf } from './types/vcfAdapter.js';
|
|
7
|
-
export {
|
|
7
|
+
export { writeTrixIndex } from './writeTrixIndex.js';
|
package/esm/indexFiles.d.ts
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
import type { Track } from './util.ts';
|
|
1
|
+
import type { IndexingPolicy, Track } from './util.ts';
|
|
2
2
|
export interface TrackIndexProgress {
|
|
3
3
|
onStart?: (totalBytes: number) => void;
|
|
4
4
|
onUpdate?: (processedBytes: number) => void;
|
|
5
5
|
onDone?: () => void;
|
|
6
6
|
}
|
|
7
|
-
export declare function indexFiles({ tracks,
|
|
7
|
+
export declare function indexFiles({ tracks, policy, outDir, makeProgress, checkAbort, }: {
|
|
8
8
|
tracks: Track[];
|
|
9
|
-
|
|
9
|
+
policy: IndexingPolicy;
|
|
10
10
|
outDir: string;
|
|
11
|
-
featureTypesToExclude: string[];
|
|
12
|
-
featureTypesToInclude?: string[];
|
|
13
11
|
makeProgress?: (trackId: string) => TrackIndexProgress;
|
|
14
12
|
checkAbort?: () => void;
|
|
15
13
|
}): AsyncGenerator<string, void, unknown>;
|
package/esm/indexFiles.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { indexGff3 } from './types/gff3Adapter.js';
|
|
2
2
|
import { indexGtf } from './types/gtfAdapter.js';
|
|
3
3
|
import { indexVcf } from './types/vcfAdapter.js';
|
|
4
|
-
import { indexableAdapters } from './util.js';
|
|
4
|
+
import { indexableAdapters, trackIndexingPolicy } from './util.js';
|
|
5
5
|
function getIndexingLocation(track, locationKey) {
|
|
6
6
|
const { adapter } = track;
|
|
7
7
|
// adapter[locationKey] is the canonical location object, e.g. gffGzLocation;
|
|
@@ -11,23 +11,21 @@ function getIndexingLocation(track, locationKey) {
|
|
|
11
11
|
return loc?.locationType === 'LocalPathLocation' ? loc.localPath : loc?.uri;
|
|
12
12
|
}
|
|
13
13
|
const noop = () => { };
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
// exclude/include overrides from textSearching take precedence over the
|
|
17
|
-
// defaults.
|
|
18
|
-
export async function* indexFiles({ tracks, attributesToIndex, outDir, featureTypesToExclude, featureTypesToInclude, makeProgress, checkAbort, }) {
|
|
14
|
+
// Streams index records for a set of tracks, each read under its own policy
|
|
15
|
+
export async function* indexFiles({ tracks, policy, outDir, makeProgress, checkAbort, }) {
|
|
19
16
|
for (const track of tracks) {
|
|
20
17
|
checkAbort?.();
|
|
21
|
-
const { adapter,
|
|
18
|
+
const { adapter, trackId } = track;
|
|
22
19
|
const indexable = indexableAdapters[adapter?.type ?? ''];
|
|
23
20
|
const inLocation = indexable
|
|
24
21
|
? getIndexingLocation(track, indexable.locationKey)
|
|
25
22
|
: undefined;
|
|
26
23
|
if (indexable && inLocation) {
|
|
27
24
|
const progress = makeProgress?.(trackId);
|
|
25
|
+
const { attributes, exclude, include } = trackIndexingPolicy(track, policy);
|
|
28
26
|
const common = {
|
|
29
27
|
config: track,
|
|
30
|
-
attributesToIndex:
|
|
28
|
+
attributesToIndex: attributes,
|
|
31
29
|
inLocation,
|
|
32
30
|
outDir,
|
|
33
31
|
onStart: progress?.onStart ?? noop,
|
|
@@ -37,10 +35,8 @@ export async function* indexFiles({ tracks, attributesToIndex, outDir, featureTy
|
|
|
37
35
|
if (indexable.format === 'gff3') {
|
|
38
36
|
yield* indexGff3({
|
|
39
37
|
...common,
|
|
40
|
-
featureTypesToExclude:
|
|
41
|
-
|
|
42
|
-
featureTypesToInclude: textSearching?.indexingFeatureTypesToInclude ??
|
|
43
|
-
featureTypesToInclude,
|
|
38
|
+
featureTypesToExclude: exclude,
|
|
39
|
+
featureTypesToInclude: include,
|
|
44
40
|
});
|
|
45
41
|
}
|
|
46
42
|
else if (indexable.format === 'gtf') {
|
package/esm/trixPaths.d.ts
CHANGED
|
@@ -5,11 +5,8 @@ export declare function sanitizeForFilename(name: string): string;
|
|
|
5
5
|
* The three files an index called `name` writes, sanitized once.
|
|
6
6
|
*
|
|
7
7
|
* Everything that writes a trix artifact or points a config at one derives its
|
|
8
|
-
* paths from here
|
|
9
|
-
* the
|
|
10
|
-
* `createTrixAdapter` sanitized, so a trackId holding a `/` aimed the write at
|
|
11
|
-
* a `trix/` subdirectory that does not exist, and the rest of the
|
|
12
|
-
* Windows-invalid set wrote a file no search would look for.
|
|
8
|
+
* paths from here, so a trackId holding a `/` or another Windows-invalid
|
|
9
|
+
* character names the same file for the writer as for the search reading it.
|
|
13
10
|
*/
|
|
14
11
|
export declare function trixFileNames(name: string): {
|
|
15
12
|
ix: string;
|
package/esm/trixPaths.js
CHANGED
|
@@ -17,11 +17,8 @@ export function sanitizeForFilename(name) {
|
|
|
17
17
|
* The three files an index called `name` writes, sanitized once.
|
|
18
18
|
*
|
|
19
19
|
* Everything that writes a trix artifact or points a config at one derives its
|
|
20
|
-
* paths from here
|
|
21
|
-
* the
|
|
22
|
-
* `createTrixAdapter` sanitized, so a trackId holding a `/` aimed the write at
|
|
23
|
-
* a `trix/` subdirectory that does not exist, and the rest of the
|
|
24
|
-
* Windows-invalid set wrote a file no search would look for.
|
|
20
|
+
* paths from here, so a trackId holding a `/` or another Windows-invalid
|
|
21
|
+
* character names the same file for the writer as for the search reading it.
|
|
25
22
|
*/
|
|
26
23
|
export function trixFileNames(name) {
|
|
27
24
|
const safeName = sanitizeForFilename(name);
|
package/esm/types/common.d.ts
CHANGED
|
@@ -12,12 +12,3 @@ export declare function createReadlineInterface(stream: Readable, inLocation: st
|
|
|
12
12
|
export declare function parseAttributes(infoString: string, decodeFunc: (s: string) => string): Record<string, string | undefined>;
|
|
13
13
|
export declare function makeLocation(location: string, protocol: string): UriLocation | LocalPathLocation;
|
|
14
14
|
export declare function guessAdapterFromFileName(filePath: string): Track;
|
|
15
|
-
export declare function generateMeta({ configs, attributesToIndex, outDir, name, featureTypesToExclude, featureTypesToInclude, assemblyNames, }: {
|
|
16
|
-
configs: Track[];
|
|
17
|
-
attributesToIndex: string[];
|
|
18
|
-
outDir: string;
|
|
19
|
-
name: string;
|
|
20
|
-
featureTypesToExclude: string[];
|
|
21
|
-
featureTypesToInclude?: string[];
|
|
22
|
-
assemblyNames: string[];
|
|
23
|
-
}): void;
|
package/esm/types/common.js
CHANGED
|
@@ -5,7 +5,6 @@ import readline from 'node:readline';
|
|
|
5
5
|
import { Readable } from 'node:stream';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
import { createGunzip } from 'node:zlib';
|
|
8
|
-
import { trixFilePaths } from '../trixPaths.js';
|
|
9
8
|
import { indexableAdapters } from '../util.js';
|
|
10
9
|
export function isURL(fileName) {
|
|
11
10
|
try {
|
|
@@ -175,21 +174,3 @@ export function guessAdapterFromFileName(filePath) {
|
|
|
175
174
|
throw new Error(`Unsupported file type ${filePath}`);
|
|
176
175
|
}
|
|
177
176
|
}
|
|
178
|
-
export function generateMeta({ configs, attributesToIndex, outDir, name, featureTypesToExclude, featureTypesToInclude, assemblyNames, }) {
|
|
179
|
-
fs.writeFileSync(trixFilePaths(outDir, name).meta, JSON.stringify({
|
|
180
|
-
dateCreated: new Date().toISOString(),
|
|
181
|
-
tracks: configs.map(config => {
|
|
182
|
-
const { trackId, textSearching, adapter } = config;
|
|
183
|
-
return {
|
|
184
|
-
trackId,
|
|
185
|
-
attributesIndexed: textSearching?.indexingAttributes ?? attributesToIndex,
|
|
186
|
-
excludedTypes: textSearching?.indexingFeatureTypesToExclude ??
|
|
187
|
-
featureTypesToExclude,
|
|
188
|
-
includedTypes: textSearching?.indexingFeatureTypesToInclude ??
|
|
189
|
-
featureTypesToInclude,
|
|
190
|
-
adapterConf: adapter,
|
|
191
|
-
};
|
|
192
|
-
}),
|
|
193
|
-
assemblyNames,
|
|
194
|
-
}, null, 2));
|
|
195
|
-
}
|
package/esm/types/gff3Adapter.js
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
|
-
import { decodeURIComponentNoThrow } from '../util.js';
|
|
1
|
+
import { decodeURIComponentNoThrow, trixLine } from '../util.js';
|
|
2
2
|
import { createReadlineInterface, getLocalOrRemoteStream, parseAttributes, } from './common.js';
|
|
3
|
+
// GENCODE writes no `Name`: a gene row carries `gene_name`, a transcript row
|
|
4
|
+
// `transcript_name`, and every row repeats its parents' names too. So `Name`
|
|
5
|
+
// falls back to the name whose id is this row's own ID, which leaves a UTR or
|
|
6
|
+
// codon row unnamed rather than answering a search for its transcript.
|
|
7
|
+
function ownName(attrs) {
|
|
8
|
+
const id = attrs.ID;
|
|
9
|
+
return id === undefined
|
|
10
|
+
? undefined
|
|
11
|
+
: id === attrs.transcript_id
|
|
12
|
+
? attrs.transcript_name
|
|
13
|
+
: id === attrs.gene_id
|
|
14
|
+
? attrs.gene_name
|
|
15
|
+
: undefined;
|
|
16
|
+
}
|
|
3
17
|
/**
|
|
4
18
|
* Stream one GFF3 into trix records, one line per indexed feature.
|
|
5
19
|
*
|
|
@@ -35,7 +49,6 @@ export async function* indexGff3({ config, attributesToIndex, inLocation, outDir
|
|
|
35
49
|
const includeSet = featureTypesToInclude?.length
|
|
36
50
|
? new Set(featureTypesToInclude)
|
|
37
51
|
: undefined;
|
|
38
|
-
const encodedTrackId = encodeURIComponent(trackId);
|
|
39
52
|
for await (const line of rl) {
|
|
40
53
|
checkAbort?.();
|
|
41
54
|
if (!line.trim() || line.startsWith('#')) {
|
|
@@ -59,14 +72,11 @@ export async function* indexGff3({ config, attributesToIndex, inLocation, outDir
|
|
|
59
72
|
(includeSet === undefined || includeSet.has(type))) {
|
|
60
73
|
const col9attrs = parseAttributes(col9, decodeURIComponentNoThrow);
|
|
61
74
|
const attrs = attributesToIndex
|
|
62
|
-
.map(attr => col9attrs[attr]
|
|
75
|
+
.map(attr => col9attrs[attr] ??
|
|
76
|
+
(attr === 'Name' ? ownName(col9attrs) : undefined))
|
|
63
77
|
.filter((f) => !!f);
|
|
64
78
|
if (attrs.length > 0) {
|
|
65
|
-
|
|
66
|
-
const encodedAttrs = attrs.map(a => `"${encodeURIComponent(a)}"`);
|
|
67
|
-
const record = `["${encodeURIComponent(locStr)}"|"${encodedTrackId}"|${encodedAttrs.join('|')}]`;
|
|
68
|
-
const uniqueAttrs = [...new Set(attrs)];
|
|
69
|
-
yield `${record} ${uniqueAttrs.join(' ')}\n`;
|
|
79
|
+
yield trixLine(`${seq_id}:${start}..${end}`, trackId, attrs);
|
|
70
80
|
}
|
|
71
81
|
}
|
|
72
82
|
}
|
package/esm/types/gtfAdapter.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { trixLine } from '../util.js';
|
|
1
2
|
import { createReadlineInterface, getLocalOrRemoteStream } from './common.js';
|
|
2
3
|
// GFF3-style attribute names have no GTF equivalent, so the shared defaults
|
|
3
4
|
// (`Name`, `ID`, `symbol`) would index nothing. Each requested name also pulls
|
|
@@ -82,7 +83,6 @@ export async function* indexGtf({ config, attributesToIndex, inLocation, outDir,
|
|
|
82
83
|
onUpdate,
|
|
83
84
|
});
|
|
84
85
|
const rl = createReadlineInterface(stream, inLocation);
|
|
85
|
-
const encodedTrackId = encodeURIComponent(trackId);
|
|
86
86
|
const attributeNames = expandAttributeNames(attributesToIndex);
|
|
87
87
|
const groups = new Map();
|
|
88
88
|
function accumulate(key, refName, start, end, values) {
|
|
@@ -141,9 +141,6 @@ export async function* indexGtf({ config, attributesToIndex, inLocation, outDir,
|
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
143
|
for (const { refName, start, end, attrs } of groups.values()) {
|
|
144
|
-
|
|
145
|
-
const encodedAttrs = [...attrs].map(a => `"${encodeURIComponent(a)}"`);
|
|
146
|
-
const record = `["${encodeURIComponent(locStr)}"|"${encodedTrackId}"|${encodedAttrs.join('|')}]`;
|
|
147
|
-
yield `${record} ${[...attrs].join(' ')}\n`;
|
|
144
|
+
yield trixLine(`${refName}:${start}..${end}`, trackId, [...attrs]);
|
|
148
145
|
}
|
|
149
146
|
}
|
package/esm/types/vcfAdapter.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { decodeURIComponentNoThrow } from '../util.js';
|
|
1
|
+
import { decodeURIComponentNoThrow, trixLine } from '../util.js';
|
|
2
2
|
import { createReadlineInterface, getLocalOrRemoteStream, parseAttributes, } from './common.js';
|
|
3
3
|
export async function* indexVcf({ config, attributesToIndex, inLocation, outDir, onStart, onUpdate, checkAbort, }) {
|
|
4
4
|
const { trackId } = config;
|
|
@@ -9,7 +9,6 @@ export async function* indexVcf({ config, attributesToIndex, inLocation, outDir,
|
|
|
9
9
|
onUpdate,
|
|
10
10
|
});
|
|
11
11
|
const rl = createReadlineInterface(stream, inLocation);
|
|
12
|
-
const encodedTrackId = encodeURIComponent(trackId);
|
|
13
12
|
for await (const line of rl) {
|
|
14
13
|
checkAbort?.();
|
|
15
14
|
if (!line.trim() || line.startsWith('#')) {
|
|
@@ -30,7 +29,6 @@ export async function* indexVcf({ config, attributesToIndex, inLocation, outDir,
|
|
|
30
29
|
const endNum = Number(fields.END);
|
|
31
30
|
const end = fields.END && Number.isFinite(endNum) ? endNum : Number(pos) + 1;
|
|
32
31
|
const locStr = `${ref}:${pos}..${end}`;
|
|
33
|
-
const encodedLocStr = encodeURIComponent(locStr);
|
|
34
32
|
const infoAttrs = attributesToIndex
|
|
35
33
|
.map(attr => fields[attr])
|
|
36
34
|
.filter((f) => !!f);
|
|
@@ -45,11 +43,7 @@ export async function* indexVcf({ config, attributesToIndex, inLocation, outDir,
|
|
|
45
43
|
: [infoAttrs];
|
|
46
44
|
for (const attrs of attrGroups) {
|
|
47
45
|
if (attrs.length > 0) {
|
|
48
|
-
|
|
49
|
-
// the trailing word list so trix indexes them as searchable terms
|
|
50
|
-
const encodedAttrs = attrs.map(a => `"${encodeURIComponent(a)}"`);
|
|
51
|
-
const record = `["${encodedLocStr}"|"${encodedTrackId}"|${encodedAttrs.join('|')}]`;
|
|
52
|
-
yield `${record} ${[...new Set(attrs)].join(' ')}\n`;
|
|
46
|
+
yield trixLine(locStr, trackId, attrs);
|
|
53
47
|
}
|
|
54
48
|
}
|
|
55
49
|
}
|
package/esm/util.d.ts
CHANGED
|
@@ -51,6 +51,20 @@ export interface Track {
|
|
|
51
51
|
}
|
|
52
52
|
export declare const defaultAttributesToIndex: string[];
|
|
53
53
|
export declare const defaultFeatureTypesToExclude: string[];
|
|
54
|
+
/** What an index reads out of a track's features. */
|
|
55
|
+
export interface IndexingPolicy {
|
|
56
|
+
attributes: string[];
|
|
57
|
+
/** feature types to skip (GFF3 only) */
|
|
58
|
+
exclude: string[];
|
|
59
|
+
/**
|
|
60
|
+
* the only feature types to index, narrowed by `exclude` (GFF3 only). Absent
|
|
61
|
+
* or empty means no allow list, never "index nothing". See indexGff3
|
|
62
|
+
*/
|
|
63
|
+
include?: string[];
|
|
64
|
+
}
|
|
65
|
+
export declare const defaultIndexingPolicy: IndexingPolicy;
|
|
66
|
+
/** The policy `track` is indexed under: its own settings, else the run's. */
|
|
67
|
+
export declare function trackIndexingPolicy({ textSearching }: Track, run: IndexingPolicy): IndexingPolicy;
|
|
54
68
|
export type IndexableFormat = 'gff3' | 'gtf' | 'vcf';
|
|
55
69
|
export declare const indexableAdapters: Record<string, {
|
|
56
70
|
locationKey: string;
|
|
@@ -72,5 +86,12 @@ export interface Gff3IndexerOptions extends IndexerOptions {
|
|
|
72
86
|
featureTypesToExclude: string[];
|
|
73
87
|
featureTypesToInclude?: string[];
|
|
74
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* One line of ixIxx input: the record a search hit hands back —
|
|
91
|
+
* `["loc"|"trackId"|"attr"|...]`, fields URI-encoded so neither a comma nor a
|
|
92
|
+
* space can split it — then the words the hit is found by.
|
|
93
|
+
* TrixTextSearchAdapter reads the record back.
|
|
94
|
+
*/
|
|
95
|
+
export declare function trixLine(loc: string, trackId: string, attrs: string[]): string;
|
|
75
96
|
export declare function decodeURIComponentNoThrow(uri: string): string;
|
|
76
97
|
export {};
|
package/esm/util.js
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
export const defaultAttributesToIndex = ['Name', 'ID', 'symbol'];
|
|
2
2
|
export const defaultFeatureTypesToExclude = ['exon', 'CDS'];
|
|
3
|
+
export const defaultIndexingPolicy = {
|
|
4
|
+
attributes: defaultAttributesToIndex,
|
|
5
|
+
exclude: defaultFeatureTypesToExclude,
|
|
6
|
+
};
|
|
7
|
+
/** The policy `track` is indexed under: its own settings, else the run's. */
|
|
8
|
+
export function trackIndexingPolicy({ textSearching }, run) {
|
|
9
|
+
return {
|
|
10
|
+
attributes: textSearching?.indexingAttributes ?? run.attributes,
|
|
11
|
+
exclude: textSearching?.indexingFeatureTypesToExclude ?? run.exclude,
|
|
12
|
+
include: textSearching?.indexingFeatureTypesToInclude ?? run.include,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
3
15
|
// single source of truth for what `jbrowse text-index` can index: which adapter
|
|
4
16
|
// types, where each keeps its file location, and which line parser to use.
|
|
5
17
|
// Everything else (the adapter dispatch, the CLI's supported() gate, the
|
|
@@ -15,6 +27,16 @@ export const indexableAdapters = {
|
|
|
15
27
|
export function isSupportedIndexingAdapter(type = '') {
|
|
16
28
|
return type in indexableAdapters;
|
|
17
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* One line of ixIxx input: the record a search hit hands back —
|
|
32
|
+
* `["loc"|"trackId"|"attr"|...]`, fields URI-encoded so neither a comma nor a
|
|
33
|
+
* space can split it — then the words the hit is found by.
|
|
34
|
+
* TrixTextSearchAdapter reads the record back.
|
|
35
|
+
*/
|
|
36
|
+
export function trixLine(loc, trackId, attrs) {
|
|
37
|
+
const fields = [loc, trackId, ...attrs].map(f => `"${encodeURIComponent(f)}"`);
|
|
38
|
+
return `[${fields.join('|')}] ${[...new Set(attrs)].join(' ')}\n`;
|
|
39
|
+
}
|
|
18
40
|
export function decodeURIComponentNoThrow(uri) {
|
|
19
41
|
try {
|
|
20
42
|
return decodeURIComponent(uri);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { TrackIndexProgress } from './indexFiles.ts';
|
|
2
|
+
import type { IndexingPolicy, Track } from './util.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Index `tracks` into `<outDir>/trix/<name>.ix`, `.ixx` and `_meta.json`.
|
|
5
|
+
*
|
|
6
|
+
* `onSort` fires once every file has been read, when the sort that writes the
|
|
7
|
+
* index begins — minutes on a large index, with no byte count to report.
|
|
8
|
+
*/
|
|
9
|
+
export declare function writeTrixIndex({ tracks, outDir, name, policy, assemblyNames, prefixSize, makeProgress, checkAbort, onSort, }: {
|
|
10
|
+
tracks: Track[];
|
|
11
|
+
outDir: string;
|
|
12
|
+
name: string;
|
|
13
|
+
policy: IndexingPolicy;
|
|
14
|
+
assemblyNames: string[];
|
|
15
|
+
prefixSize?: number;
|
|
16
|
+
makeProgress?: (trackId: string) => TrackIndexProgress;
|
|
17
|
+
checkAbort?: () => void;
|
|
18
|
+
onSort?: () => void;
|
|
19
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { Readable } from 'node:stream';
|
|
4
|
+
import { ixIxxStream } from 'ixixx';
|
|
5
|
+
import { indexFiles } from './indexFiles.js';
|
|
6
|
+
import { TRIX_DIR, trixFilePaths } from './trixPaths.js';
|
|
7
|
+
import { trackIndexingPolicy } from './util.js';
|
|
8
|
+
/**
|
|
9
|
+
* Index `tracks` into `<outDir>/trix/<name>.ix`, `.ixx` and `_meta.json`.
|
|
10
|
+
*
|
|
11
|
+
* `onSort` fires once every file has been read, when the sort that writes the
|
|
12
|
+
* index begins — minutes on a large index, with no byte count to report.
|
|
13
|
+
*/
|
|
14
|
+
export async function writeTrixIndex({ tracks, outDir, name, policy, assemblyNames, prefixSize, makeProgress, checkAbort, onSort, }) {
|
|
15
|
+
fs.mkdirSync(path.join(outDir, TRIX_DIR), { recursive: true });
|
|
16
|
+
const records = Readable.from(indexFiles({ tracks, policy, outDir, makeProgress, checkAbort }));
|
|
17
|
+
if (onSort) {
|
|
18
|
+
records.on('end', onSort);
|
|
19
|
+
}
|
|
20
|
+
const paths = trixFilePaths(outDir, name);
|
|
21
|
+
await ixIxxStream(records, paths.ix, paths.ixx, prefixSize);
|
|
22
|
+
checkAbort?.();
|
|
23
|
+
fs.writeFileSync(paths.meta, JSON.stringify({
|
|
24
|
+
dateCreated: new Date().toISOString(),
|
|
25
|
+
tracks: tracks.map(track => {
|
|
26
|
+
const { attributes, exclude, include } = trackIndexingPolicy(track, policy);
|
|
27
|
+
return {
|
|
28
|
+
trackId: track.trackId,
|
|
29
|
+
attributesIndexed: attributes,
|
|
30
|
+
excludedTypes: exclude,
|
|
31
|
+
includedTypes: include,
|
|
32
|
+
adapterConf: track.adapter,
|
|
33
|
+
};
|
|
34
|
+
}),
|
|
35
|
+
assemblyNames,
|
|
36
|
+
}, null, 2));
|
|
37
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/text-indexing-core",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "JBrowse 2 core text indexing routines for parsing GFF3 and VCF files",
|
|
6
6
|
"keywords": [
|
|
@@ -27,7 +27,9 @@
|
|
|
27
27
|
"files": [
|
|
28
28
|
"esm"
|
|
29
29
|
],
|
|
30
|
-
"dependencies": {
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"ixixx": "^3.0.13"
|
|
32
|
+
},
|
|
31
33
|
"publishConfig": {
|
|
32
34
|
"access": "public"
|
|
33
35
|
},
|