Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/orama-db-deterministic.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@doc-kit/generator-react': patch
---

`orama-db.json` is now identical between builds of the same docs: documents get a stable `href` id instead of a time-based one, and are sorted by `href`.
65 changes: 65 additions & 0 deletions packages/react/src/orama-db/__tests__/generate.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import assert from 'node:assert/strict';
import { describe, it } from 'node:test';

import { setConfig } from '@doc-kit/core/utils/configuration/index.mjs';
import { create, load, search } from '@orama/orama';
import { u } from 'unist-builder';

import { generate } from '../generate.mjs';

const config = await setConfig({ target: ['orama-db'] });

// Return the saved index instead of writing it to disk
config['orama-db'].output = undefined;

const entry = (api, path, depth, name, slug, text) => ({
api,
path,
heading: { depth, data: { name, slug } },
content: u('root', [u('paragraph', [u('text', text)])]),
});

const fs = [
entry('fs', '/fs', 1, 'File system', 'file-system', 'Files.'),
entry('fs', '/fs', 2, 'Class: FileHandle', 'class-filehandle', 'A handle.'),
entry('fs', '/fs', 3, 'readFile', 'readfile', 'Reads a file.'),
];

const http = [
entry('http', '/http', 1, 'HTTP', 'http', 'Requests.'),
entry('http', '/http', 2, 'request', 'request', 'Sends a request.'),
];

describe('orama-db', () => {
it('produces the same output on every run', async () => {
const first = await generate([...fs, ...http]);
const second = await generate([...fs, ...http]);

assert.equal(JSON.stringify(first), JSON.stringify(second));
});

it('produces the same output whatever order the modules arrive in', async () => {
const forward = await generate([...fs, ...http]);
const reversed = await generate([...http, ...fs]);

assert.equal(JSON.stringify(forward), JSON.stringify(reversed));
});

it('keeps each module hierarchical title', async () => {
const db = create({ schema: {} });
load(db, await generate([...http, ...fs]));

const { hits } = await search(db, { term: 'readFile' });

assert.equal(hits[0].document.title, 'Class: FileHandle > readFile');
});

it('can still be searched', async () => {
const db = create({ schema: {} });
load(db, await generate([...fs, ...http]));

const { hits } = await search(db, { term: 'request' });

assert.equal(hits[0].document.href, '/http.html#request');
});
});
12 changes: 11 additions & 1 deletion packages/react/src/orama-db/generate.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,27 @@ export async function generate(input) {
child => child.type === 'paragraph'
);

const href = `${entry.path}.html#${entry.heading.data.slug}`;

return {
// Orama makes up a time-based id when none is given, which would
// change the saved index on every build
id: href,
title: hierarchicalTitle,
description: paragraph
? transformNodeToString(paragraph, true)
: undefined,
href: `${entry.path}.html#${entry.heading.data.slug}`,
href,
siteSection: headings[0].heading.data.name,
};
})
);

// The saved index follows insertion order, which depends on the order the
// generator's input arrives in. Sort without a locale so it is stable on
// every machine.
documents.sort((a, b) => (a.href < b.href ? -1 : a.href > b.href ? 1 : 0));

// Insert all documents
await insertMultiple(db, documents);

Expand Down
Loading