@redpanda-data/docs-extensions-and-macros 5.1.0 → 5.1.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.
|
@@ -292,40 +292,95 @@ function generateIndex (playbook, contentCatalog, { indexLatestOnly = false, exc
|
|
|
292
292
|
? page.asciidoc.attributes['page-commercial-names'].split(',').map(name => name.trim())
|
|
293
293
|
: []
|
|
294
294
|
|
|
295
|
-
//
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
295
|
+
// Algolia only indexes roughly the first ~290 words of any single record. On
|
|
296
|
+
// long reference pages (cluster/topic properties, metrics) every property or
|
|
297
|
+
// metric name lives in the `titles` array, and there can be hundreds of them, so
|
|
298
|
+
// every name past that window is stored but NOT searchable (DOC-1878). Split the
|
|
299
|
+
// titles of such pages across multiple records, each small enough to be fully
|
|
300
|
+
// indexed. Normal pages keep a single record. Chunks after the first get a unique
|
|
301
|
+
// objectID anchored to their first heading so search results deep-link into the
|
|
302
|
+
// page; the first chunk keeps the page's base objectID.
|
|
303
|
+
const baseObjectID = urlPath + page.pub.url
|
|
304
|
+
const titleChunks = isPropertiesPage ? chunkTitles(titles) : [titles]
|
|
305
|
+
|
|
306
|
+
titleChunks.forEach((chunk, chunkIndex) => {
|
|
307
|
+
const objectID = chunkIndex === 0
|
|
308
|
+
? baseObjectID
|
|
309
|
+
: `${baseObjectID}#${chunk[0].h}`
|
|
310
|
+
|
|
311
|
+
// keywords included in index item
|
|
312
|
+
const indexItem = {
|
|
313
|
+
title: documentTitle,
|
|
314
|
+
version: version,
|
|
315
|
+
text: text,
|
|
316
|
+
intro: intro,
|
|
317
|
+
objectID: objectID,
|
|
318
|
+
// Clean page path (no #fragment) shared by every chunk of a page. The search
|
|
319
|
+
// UI builds result links from `url` and appends its own matched-heading
|
|
320
|
+
// anchor, so chunk objectIDs (which carry a #anchor for uniqueness) must not
|
|
321
|
+
// be used for the href. `url` is also the attribute to dedupe chunks on.
|
|
322
|
+
url: baseObjectID,
|
|
323
|
+
titles: chunk,
|
|
324
|
+
keywords: keywords,
|
|
325
|
+
categories: categories,
|
|
326
|
+
commercialNames: commercialNames,
|
|
327
|
+
unixTimestamp: unixTimestamp
|
|
328
|
+
}
|
|
308
329
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
330
|
+
if (component.name !== 'labs') {
|
|
331
|
+
indexItem.product = component.title
|
|
332
|
+
indexItem.breadcrumbs = breadcrumbs
|
|
333
|
+
indexItem.type = 'Doc'
|
|
334
|
+
indexItem._tags = Array.isArray(tag) ? tag : [tag]
|
|
335
|
+
} else {
|
|
336
|
+
indexItem.deployment = deployment
|
|
337
|
+
indexItem.type = 'Lab'
|
|
338
|
+
indexItem.interactive = false
|
|
339
|
+
indexItem._tags = Array.isArray(tag) ? tag : [tag]
|
|
340
|
+
}
|
|
320
341
|
|
|
321
|
-
|
|
322
|
-
|
|
342
|
+
algolia[cname][version].push(indexItem)
|
|
343
|
+
algoliaCount++
|
|
344
|
+
})
|
|
323
345
|
}
|
|
324
346
|
|
|
325
347
|
logger.info(`Indexed ${algoliaCount} pages`)
|
|
326
348
|
return algolia
|
|
327
349
|
}
|
|
328
350
|
|
|
351
|
+
/**
|
|
352
|
+
* Split a titles array into chunks whose combined token count stays within
|
|
353
|
+
* Algolia's per-record indexing window (~290 words; we leave a safety margin).
|
|
354
|
+
* Each returned chunk is small enough that every heading it contains is actually
|
|
355
|
+
* indexed for search, which keeps property/metric names on long reference pages
|
|
356
|
+
* searchable (DOC-1878).
|
|
357
|
+
*
|
|
358
|
+
* @param {Array<{t: string, h: string}>} titles - Section headings for a page.
|
|
359
|
+
* @param {number} [maxTokens=180] - Approximate token budget per chunk.
|
|
360
|
+
* @returns {Array<Array<{t: string, h: string}>>} One or more title chunks. An
|
|
361
|
+
* empty input yields a single empty chunk so the page still gets a record.
|
|
362
|
+
*/
|
|
363
|
+
function chunkTitles (titles, maxTokens = 180) {
|
|
364
|
+
if (!titles.length) return [[]]
|
|
365
|
+
const chunks = []
|
|
366
|
+
let current = []
|
|
367
|
+
let tokens = 0
|
|
368
|
+
for (const entry of titles) {
|
|
369
|
+
// Algolia tokenizes on separators (whitespace, underscores, dots, etc.), so a
|
|
370
|
+
// name like `partition_autobalancing_mode` counts as several tokens.
|
|
371
|
+
const entryTokens = String(entry.t || '').split(/[\s_./:-]+/).filter(Boolean).length || 1
|
|
372
|
+
if (current.length && tokens + entryTokens > maxTokens) {
|
|
373
|
+
chunks.push(current)
|
|
374
|
+
current = []
|
|
375
|
+
tokens = 0
|
|
376
|
+
}
|
|
377
|
+
current.push(entry)
|
|
378
|
+
tokens += entryTokens
|
|
379
|
+
}
|
|
380
|
+
if (current.length) chunks.push(current)
|
|
381
|
+
return chunks
|
|
382
|
+
}
|
|
383
|
+
|
|
329
384
|
/**
|
|
330
385
|
* Extract the path from a URL
|
|
331
386
|
* @param {string} url - The URL to extract path from
|