@gmod/bbi 9.0.9 → 9.0.12

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 (80) hide show
  1. package/README.md +70 -12
  2. package/dist/array-feature-view.d.ts +5 -6
  3. package/dist/array-feature-view.js +7 -13
  4. package/dist/array-feature-view.js.map +1 -1
  5. package/dist/bbi.js +22 -37
  6. package/dist/bbi.js.map +1 -1
  7. package/dist/bigbed.d.ts +1 -2
  8. package/dist/bigbed.js +24 -36
  9. package/dist/bigbed.js.map +1 -1
  10. package/dist/bigwig.js +1 -1
  11. package/dist/bigwig.js.map +1 -1
  12. package/dist/block-view.d.ts +1 -1
  13. package/dist/block-view.js +135 -97
  14. package/dist/block-view.js.map +1 -1
  15. package/dist/range.js +4 -1
  16. package/dist/range.js.map +1 -1
  17. package/dist/types.d.ts +0 -1
  18. package/dist/unzip.d.ts +2 -12
  19. package/dist/unzip.js +7 -15
  20. package/dist/unzip.js.map +1 -1
  21. package/dist/util.d.ts +3 -2
  22. package/dist/util.js +13 -1
  23. package/dist/util.js.map +1 -1
  24. package/dist/wasm/inflate-wasm-inlined.d.ts +21 -18
  25. package/dist/wasm/inflate-wasm-inlined.js +146 -74
  26. package/dist/wasm/package.json +1 -0
  27. package/esm/array-feature-view.d.ts +5 -6
  28. package/esm/array-feature-view.js +7 -13
  29. package/esm/array-feature-view.js.map +1 -1
  30. package/esm/bbi.js +19 -34
  31. package/esm/bbi.js.map +1 -1
  32. package/esm/bigbed.d.ts +1 -2
  33. package/esm/bigbed.js +22 -31
  34. package/esm/bigbed.js.map +1 -1
  35. package/esm/bigwig.js +1 -1
  36. package/esm/bigwig.js.map +1 -1
  37. package/esm/block-view.d.ts +1 -1
  38. package/esm/block-view.js +136 -98
  39. package/esm/block-view.js.map +1 -1
  40. package/esm/range.js +4 -1
  41. package/esm/range.js.map +1 -1
  42. package/esm/types.d.ts +0 -1
  43. package/esm/unzip.d.ts +2 -12
  44. package/esm/unzip.js +7 -15
  45. package/esm/unzip.js.map +1 -1
  46. package/esm/util.d.ts +3 -2
  47. package/esm/util.js +11 -1
  48. package/esm/util.js.map +1 -1
  49. package/esm/wasm/inflate-wasm-inlined.d.ts +21 -18
  50. package/esm/wasm/inflate-wasm-inlined.js +145 -67
  51. package/package.json +23 -22
  52. package/src/array-feature-view.ts +15 -26
  53. package/src/bbi.ts +20 -36
  54. package/src/bigbed.ts +22 -38
  55. package/src/bigwig.ts +2 -2
  56. package/src/block-view.ts +189 -122
  57. package/src/range.ts +4 -3
  58. package/src/types.ts +0 -1
  59. package/src/unzip.ts +11 -24
  60. package/src/util.ts +21 -2
  61. package/src/wasm/inflate-wasm-inlined.d.ts +21 -0
  62. package/src/wasm/inflate-wasm-inlined.js +150 -170
  63. package/src/wasm/inflate_wasm.js +1 -1
  64. package/src/wasm/inflate_wasm_bg.js +2 -3
  65. package/src/wasm/inflate_wasm_bg.wasm +0 -0
  66. package/dist/wasm/inflate-wasm-inlined.js.map +0 -1
  67. package/dist/wasm/inflate_wasm.d.ts +0 -1
  68. package/dist/wasm/inflate_wasm.js +0 -49
  69. package/dist/wasm/inflate_wasm.js.map +0 -1
  70. package/dist/wasm/inflate_wasm_bg.d.ts +0 -68
  71. package/dist/wasm/inflate_wasm_bg.js +0 -306
  72. package/dist/wasm/inflate_wasm_bg.js.map +0 -1
  73. package/esm/wasm/inflate-wasm-inlined.js.map +0 -1
  74. package/esm/wasm/inflate_wasm.d.ts +0 -1
  75. package/esm/wasm/inflate_wasm.js +0 -6
  76. package/esm/wasm/inflate_wasm.js.map +0 -1
  77. package/esm/wasm/inflate_wasm_bg.d.ts +0 -68
  78. package/esm/wasm/inflate_wasm_bg.js +0 -295
  79. package/esm/wasm/inflate_wasm_bg.js.map +0 -1
  80. package/src/wasm/inflate_wasm_bg.wasm.d.ts +0 -13
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gmod/bbi",
3
- "version": "9.0.9",
3
+ "version": "9.0.12",
4
4
  "description": "Parser for BigWig/BigBed files",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -8,7 +8,7 @@
8
8
  "url": "https://github.com/GMOD/bbi-js.git"
9
9
  },
10
10
  "type": "module",
11
- "types": "./dist/index.d.ts",
11
+ "main": "dist/index.js",
12
12
  "exports": {
13
13
  "import": "./esm/index.js",
14
14
  "require": "./dist/index.js"
@@ -24,21 +24,23 @@
24
24
  "src"
25
25
  ],
26
26
  "scripts": {
27
- "test": "vitest",
28
- "benchonly": "vitest bench",
29
- "bench": "./scripts/build-both-branches.sh \"$BRANCH1\" \"$BRANCH2\" && vitest bench",
30
- "lint": "eslint --report-unused-disable-directives --max-warnings 0",
31
- "format": "prettier --write .",
27
+ "test": "vitest --run",
28
+ "test:watch": "vitest",
29
+ "test:pack": "./scripts/test-pack.sh",
32
30
  "clean": "rimraf dist esm",
31
+ "format": "prettier --write .",
32
+ "lint": "eslint --report-unused-disable-directives --max-warnings 0",
33
33
  "prebuild": "pnpm clean",
34
- "build:wasm": "pnpm --filter inflate-wasm-build build",
35
34
  "build:esm": "tsc --outDir esm",
35
+ "postbuild:esm": "mkdir -p esm/wasm && cp src/wasm/inflate-wasm-inlined.js src/wasm/inflate-wasm-inlined.d.ts esm/wasm/",
36
36
  "build:es5": "tsc --module commonjs --moduleResolution bundler --outDir dist",
37
- "postbuild:es5": "echo '{\"type\": \"commonjs\"}' > dist/package.json",
37
+ "postbuild:es5": "echo '{\"type\": \"commonjs\"}' > dist/package.json && mkdir -p dist/wasm && cp src/wasm/inflate-wasm-inlined.js src/wasm/inflate-wasm-inlined.d.ts dist/wasm/ && echo '{\"type\": \"module\"}' > dist/wasm/package.json",
38
+ "preversion": "pnpm lint && pnpm test && pnpm build && pnpm test:pack",
39
+ "postversion": "git push --follow-tags",
38
40
  "build": "pnpm build:wasm && pnpm build:esm && pnpm build:es5",
39
- "preversion": "pnpm lint && pnpm test --run && pnpm build",
40
- "version": "standard-changelog && git add CHANGELOG.md",
41
- "postversion": "git push --follow-tags"
41
+ "benchonly": "vitest bench",
42
+ "bench": "./scripts/build-both-branches.sh \"$BRANCH1\" \"$BRANCH2\" && vitest bench",
43
+ "build:wasm": "pnpm --filter inflate-wasm-build build"
42
44
  },
43
45
  "keywords": [
44
46
  "bionode",
@@ -56,18 +58,17 @@
56
58
  "devDependencies": {
57
59
  "@eslint/js": "^10.0.1",
58
60
  "@gmod/bed": "^2.1.10",
59
- "@types/node": "^25.5.0",
60
- "@vitest/coverage-v8": "^4.1.2",
61
- "eslint": "^9.39.4",
62
- "eslint-plugin-import": "^2.32.0",
61
+ "@types/node": "^25.6.0",
62
+ "@vitest/coverage-v8": "^4.1.5",
63
+ "eslint": "^10.2.1",
64
+ "eslint-plugin-import-x": "^4.16.2",
63
65
  "eslint-plugin-unicorn": "^64.0.0",
64
- "prettier": "^3.8.1",
66
+ "prettier": "^3.8.3",
65
67
  "rimraf": "^6.1.3",
66
- "standard-changelog": "^7.0.1",
67
- "typescript": "^6.0.2",
68
- "typescript-eslint": "^8.58.0",
69
- "vitest": "^4.1.2",
70
- "webpack": "^5.105.4",
68
+ "typescript": "^6.0.3",
69
+ "typescript-eslint": "^8.59.0",
70
+ "vitest": "^4.1.5",
71
+ "webpack": "^5.106.2",
71
72
  "webpack-cli": "^7.0.2"
72
73
  },
73
74
  "publishConfig": {
@@ -10,8 +10,7 @@ export class BigWigFeature {
10
10
  get(key: 'start' | 'end' | 'score'): number
11
11
  get(key: 'minScore' | 'maxScore'): number | undefined
12
12
  get(key: 'summary'): boolean
13
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
- get(key: string): any
13
+ get(key: string): string | number | boolean | undefined
15
14
  get(key: string) {
16
15
  return this.view.get(this.i, key)
17
16
  }
@@ -43,8 +42,8 @@ export class ArrayFeatureView {
43
42
  public readonly minScores: Float32Array | undefined
44
43
  public readonly maxScores: Float32Array | undefined
45
44
  public readonly isSummary: boolean
46
- private _source: string
47
- private _refName: string
45
+ public readonly source: string
46
+ public readonly refName: string
48
47
 
49
48
  constructor(
50
49
  arrays: BigWigFeatureArrays | SummaryFeatureArrays,
@@ -57,51 +56,41 @@ export class ArrayFeatureView {
57
56
  this.isSummary = arrays.isSummary
58
57
  this.minScores = arrays.isSummary ? arrays.minScores : undefined
59
58
  this.maxScores = arrays.isSummary ? arrays.maxScores : undefined
60
- this._source = source
61
- this._refName = refName
59
+ this.source = source
60
+ this.refName = refName
62
61
  }
63
62
 
64
63
  get length() {
65
64
  return this.starts.length
66
65
  }
67
66
 
68
- get source() {
69
- return this._source
70
- }
71
-
72
- get refName() {
73
- return this._refName
74
- }
75
-
76
- start(i: number) {
67
+ start(i: number): number {
77
68
  return this.starts[i]!
78
69
  }
79
70
 
80
- end(i: number) {
71
+ end(i: number): number {
81
72
  return this.ends[i]!
82
73
  }
83
74
 
84
- score(i: number) {
75
+ score(i: number): number {
85
76
  return this.scores[i]!
86
77
  }
87
78
 
88
- minScore(i: number) {
79
+ minScore(i: number): number | undefined {
89
80
  return this.minScores?.[i]
90
81
  }
91
82
 
92
- maxScore(i: number) {
83
+ maxScore(i: number): number | undefined {
93
84
  return this.maxScores?.[i]
94
85
  }
95
86
 
96
87
  id(i: number) {
97
- return `${this._source}:${this._refName}:${this.starts[i]}-${this.ends[i]}`
88
+ return `${this.source}:${this.refName}:${this.starts[i]}-${this.ends[i]}`
98
89
  }
99
90
 
100
91
  get(i: number, key: 'refName' | 'source'): string
101
- get(
102
- i: number,
103
- key: 'start' | 'end' | 'score' | 'minScore' | 'maxScore',
104
- ): number | undefined
92
+ get(i: number, key: 'start' | 'end' | 'score'): number
93
+ get(i: number, key: 'minScore' | 'maxScore'): number | undefined
105
94
  get(i: number, key: 'summary'): boolean
106
95
 
107
96
  get(i: number, key: string): string | number | boolean | undefined
@@ -114,9 +103,9 @@ export class ArrayFeatureView {
114
103
  case 'score':
115
104
  return this.scores[i]
116
105
  case 'refName':
117
- return this._refName
106
+ return this.refName
118
107
  case 'source':
119
- return this._source
108
+ return this.source
120
109
  case 'minScore':
121
110
  return this.minScores?.[i]
122
111
  case 'maxScore':
package/src/bbi.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { LocalFile, RemoteFile } from 'generic-filehandle2'
2
2
 
3
3
  import { BlockView } from './block-view.ts'
4
+ import { getDataView, parseKey } from './util.ts'
4
5
 
5
6
  import type {
6
7
  BigWigFeatureArrays,
@@ -20,10 +21,6 @@ const BIG_BED_MAGIC = -2021002517
20
21
 
21
22
  const decoder = new TextDecoder('utf8')
22
23
 
23
- function getDataView(buffer: Uint8Array) {
24
- return new DataView(buffer.buffer, buffer.byteOffset, buffer.length)
25
- }
26
-
27
24
  export abstract class BBI {
28
25
  protected bbi: GenericFilehandle
29
26
 
@@ -119,15 +116,13 @@ export abstract class BBI {
119
116
  for (let i = 0; i < numZoomLevels; i++) {
120
117
  const reductionLevel = dataView.getUint32(offset, true)
121
118
  offset += 4
122
- const reserved = dataView.getUint32(offset, true)
123
- offset += 4
119
+ offset += 4 // reserved
124
120
  const dataOffset = Number(dataView.getBigUint64(offset, true))
125
121
  offset += 8
126
122
  const indexOffset = Number(dataView.getBigUint64(offset, true))
127
123
  offset += 8
128
124
  zoomLevels.push({
129
125
  reductionLevel,
130
- reserved,
131
126
  dataOffset,
132
127
  indexOffset,
133
128
  })
@@ -143,30 +138,25 @@ export abstract class BBI {
143
138
 
144
139
  let totalSummary: Statistics
145
140
  if (totalSummaryOffset) {
146
- const b2 = b.subarray(totalSummaryOffset)
147
- let offset = 0
148
- const dataView = getDataView(b2)
149
- const basesCovered = Number(dataView.getBigUint64(offset, true))
150
- offset += 8
151
- const scoreMin = dataView.getFloat64(offset, true)
152
- offset += 8
153
- const scoreMax = dataView.getFloat64(offset, true)
154
- offset += 8
155
- const scoreSum = dataView.getFloat64(offset, true)
156
- offset += 8
157
- const scoreSumSquares = dataView.getFloat64(offset, true)
158
-
141
+ const summaryView = getDataView(b, totalSummaryOffset)
159
142
  totalSummary = {
160
- scoreMin,
161
- scoreMax,
162
- scoreSum,
163
- scoreSumSquares,
164
- basesCovered,
143
+ basesCovered: Number(summaryView.getBigUint64(0, true)),
144
+ scoreMin: summaryView.getFloat64(8, true),
145
+ scoreMax: summaryView.getFloat64(16, true),
146
+ scoreSum: summaryView.getFloat64(24, true),
147
+ scoreSumSquares: summaryView.getFloat64(32, true),
165
148
  }
166
149
  } else {
167
150
  throw new Error('no stats')
168
151
  }
169
152
 
153
+ let autoSql = ''
154
+ if (asOffset) {
155
+ const nullPos = b.indexOf(0, asOffset)
156
+ const end = nullPos === -1 ? b.length : nullPos
157
+ autoSql = decoder.decode(b.subarray(asOffset, end))
158
+ }
159
+
170
160
  return {
171
161
  zoomLevels,
172
162
  magic,
@@ -183,9 +173,7 @@ export abstract class BBI {
183
173
  unzoomedIndexOffset,
184
174
  fileType,
185
175
  version,
186
- autoSql: asOffset
187
- ? decoder.decode(b.subarray(asOffset, b.indexOf(0, asOffset)))
188
- : '',
176
+ autoSql,
189
177
  }
190
178
  }
191
179
 
@@ -209,7 +197,7 @@ export abstract class BBI {
209
197
 
210
198
  // Recursively traverses the B+ tree to populate chromosome name-to-ID mappings
211
199
  const readBPlusTreeNode = async (currentOffset: number) => {
212
- const header = getDataView(await this.bbi.read(4, currentOffset))
200
+ const header = getDataView(await this.bbi.read(4, currentOffset, opts))
213
201
  const isLeafNode = header.getUint8(0)
214
202
  const count = header.getUint16(2, true)
215
203
 
@@ -218,16 +206,12 @@ export abstract class BBI {
218
206
  const b = await this.bbi.read(
219
207
  count * (keySize + valSize),
220
208
  currentOffset + 4,
209
+ opts,
221
210
  )
222
211
  const dataView = getDataView(b)
223
212
  let offset = 0
224
213
  for (let n = 0; n < count; n++) {
225
- const keyEnd = b.indexOf(0, offset)
226
- const effectiveKeyEnd =
227
- keyEnd !== -1 && keyEnd < offset + keySize
228
- ? keyEnd
229
- : offset + keySize
230
- const key = decoder.decode(b.subarray(offset, effectiveKeyEnd))
214
+ const key = parseKey(b, offset, keySize)
231
215
  offset += keySize
232
216
  const refId = dataView.getUint32(offset, true)
233
217
  offset += 4
@@ -239,7 +223,7 @@ export abstract class BBI {
239
223
  } else {
240
224
  // Non-leaf nodes contain pointers to child nodes
241
225
  const dataView = getDataView(
242
- await this.bbi.read(count * (keySize + 8), currentOffset + 4),
226
+ await this.bbi.read(count * (keySize + 8), currentOffset + 4, opts),
243
227
  )
244
228
  const nextNodes = []
245
229
  let offset = 0
package/src/bigbed.ts CHANGED
@@ -1,13 +1,9 @@
1
- import AbortablePromiseCache from '@gmod/abortable-promise-cache'
2
- import QuickLRU from '@jbrowse/quick-lru'
3
-
4
1
  import { BBI } from './bbi.ts'
2
+ import { getDataView, parseKey } from './util.ts'
5
3
 
6
4
  import type { RequestOptions } from './types.ts'
7
5
  import type { GenericFilehandle } from 'generic-filehandle2'
8
6
 
9
- const decoder = new TextDecoder('utf8')
10
-
11
7
  interface Loc {
12
8
  key: string
13
9
  offset: number
@@ -38,14 +34,6 @@ function getTabField(str: string, fieldIndex: number) {
38
34
  return end === -1 ? str.slice(start) : str.slice(start, end)
39
35
  }
40
36
 
41
- // Parses a null-terminated string key from a B+ tree node
42
- function parseKey(buffer: Uint8Array, offset: number, keySize: number) {
43
- const keyEnd = buffer.indexOf(0, offset)
44
- const effectiveKeyEnd =
45
- keyEnd !== -1 && keyEnd < offset + keySize ? keyEnd : offset + keySize
46
- return decoder.decode(buffer.subarray(offset, effectiveKeyEnd))
47
- }
48
-
49
37
  // Recursively traverses a B+ tree to search for a specific name in the BigBed extraIndex
50
38
  // B+ trees are balanced tree structures optimized for disk-based searches
51
39
  async function readBPlusTreeNode(
@@ -60,7 +48,7 @@ async function readBPlusTreeNode(
60
48
  ): Promise<Loc | undefined> {
61
49
  const len = 4 + blockSize * (keySize + valSize)
62
50
  const buffer = await bbi.read(len, nodeOffset, opts)
63
- const dataView = new DataView(buffer.buffer, buffer.byteOffset, buffer.length)
51
+ const dataView = getDataView(buffer)
64
52
  const nodeType = dataView.getInt8(0)
65
53
  const cnt = dataView.getInt16(2, true)
66
54
  let offset = 4
@@ -79,25 +67,21 @@ async function readBPlusTreeNode(
79
67
  })
80
68
  }
81
69
 
82
- // Binary search to find the appropriate child node
83
70
  let left = 0
84
71
  let right = leafkeys.length - 1
85
- let targetIndex = leafkeys.length - 1
72
+ let targetIndex = -1
86
73
 
87
74
  while (left <= right) {
88
75
  const mid = Math.floor((left + right) / 2)
89
- const cmp = name.localeCompare(leafkeys[mid]!.key)
90
-
91
- if (cmp < 0) {
92
- targetIndex = mid - 1
93
- right = mid - 1
94
- } else {
76
+ if (name.localeCompare(leafkeys[mid]!.key) >= 0) {
77
+ targetIndex = mid
95
78
  left = mid + 1
79
+ } else {
80
+ right = mid - 1
96
81
  }
97
82
  }
98
83
 
99
- const childOffset =
100
- targetIndex >= 0 ? leafkeys[targetIndex]!.offset : leafkeys[0]!.offset
84
+ const childOffset = leafkeys[Math.max(targetIndex, 0)]!.offset
101
85
  return readBPlusTreeNode(
102
86
  bbi,
103
87
  childOffset,
@@ -149,15 +133,16 @@ async function readBPlusTreeNode(
149
133
  }
150
134
 
151
135
  export class BigBed extends BBI {
152
- public readIndicesCache = new AbortablePromiseCache<RequestOptions, Index[]>({
153
- cache: new QuickLRU({ maxSize: 1 }),
154
- fill: (args: RequestOptions, signal?: AbortSignal) =>
155
- this._readIndices({ ...args, signal }),
156
- })
136
+ private indicesP?: Promise<Index[]>
157
137
 
158
138
  public readIndices(opts: RequestOptions = {}) {
159
- const { signal, ...rest } = opts
160
- return this.readIndicesCache.get(JSON.stringify(rest), opts, signal)
139
+ if (!this.indicesP) {
140
+ this.indicesP = this._readIndices(opts).catch((e: unknown) => {
141
+ this.indicesP = undefined
142
+ throw e
143
+ })
144
+ }
145
+ return this.indicesP
161
146
  }
162
147
 
163
148
  /*
@@ -176,9 +161,9 @@ export class BigBed extends BBI {
176
161
  */
177
162
  private async _readIndices(opts: RequestOptions) {
178
163
  const { extHeaderOffset } = await this.getHeader(opts)
179
- const b = await this.bbi.read(64, extHeaderOffset)
164
+ const b = await this.bbi.read(64, extHeaderOffset, opts)
180
165
 
181
- const dataView = new DataView(b.buffer, b.byteOffset, b.length)
166
+ const dataView = getDataView(b)
182
167
  const count = dataView.getUint16(2, true)
183
168
  const dataOffset = Number(dataView.getBigUint64(4, true))
184
169
 
@@ -189,13 +174,12 @@ export class BigBed extends BBI {
189
174
 
190
175
  const blocklen = 20
191
176
  const len = blocklen * count
192
- const buffer = await this.bbi.read(len, dataOffset)
177
+ const buffer = await this.bbi.read(len, dataOffset, opts)
193
178
 
194
179
  const indices: Index[] = []
195
180
 
196
181
  for (let i = 0; i < count; i += 1) {
197
- const b = buffer.subarray(i * blocklen)
198
- const dataView = new DataView(b.buffer, b.byteOffset, b.length)
182
+ const dataView = getDataView(buffer, i * blocklen)
199
183
  const type = dataView.getInt16(0, true)
200
184
  const fieldcount = dataView.getInt16(2, true)
201
185
  const dataOffset = Number(dataView.getBigUint64(4, true))
@@ -232,7 +216,7 @@ export class BigBed extends BBI {
232
216
  const { offset: offset2, field } = index
233
217
  const b = await this.bbi.read(32, offset2, opts)
234
218
 
235
- const dataView = new DataView(b.buffer, b.byteOffset, b.length)
219
+ const dataView = getDataView(b)
236
220
  const blockSize = dataView.getInt32(4, true)
237
221
  const keySize = dataView.getInt32(8, true)
238
222
  const valSize = dataView.getInt32(12, true)
@@ -280,7 +264,7 @@ export class BigBed extends BBI {
280
264
  if (!f.rest) {
281
265
  return false
282
266
  }
283
- const fieldIndex = (f.field || 0) - 3
267
+ const fieldIndex = (f.field ?? 0) - 3
284
268
  return getTabField(f.rest, fieldIndex) === name
285
269
  })
286
270
  }
package/src/bigwig.ts CHANGED
@@ -18,8 +18,8 @@ export class BigWig extends BBI {
18
18
  const maxLevel = zoomLevels.length - 1
19
19
 
20
20
  for (let i = maxLevel; i >= 0; i -= 1) {
21
- const zh = zoomLevels[i]
22
- if (zh && zh.reductionLevel <= 2 * basesPerPx) {
21
+ const zh = zoomLevels[i]!
22
+ if (zh.reductionLevel <= 2 * basesPerPx) {
23
23
  return this.getOrCreateBlockView(
24
24
  refsByName,
25
25
  zh.indexOffset,