Compare commits

...

2 Commits

Author SHA1 Message Date
Viktor Renkema 350f1c9808 changeset 2026-11-02 11:31:04 +01:00
Viktor Renkema 5627e76fe0 fix: ignore category references when resolving assigned tags 2026-11-02 11:30:56 +01:00
5 changed files with 82 additions and 6 deletions
@@ -0,0 +1,5 @@
---
"gitbook": patch
---
Ignore tag category references when displaying assigned tags and update filters.
@@ -145,7 +145,11 @@ describe('getDocumentSections', () => {
type: 'update',
data: {
date: '2026-04-08',
tags: [{ kind: 'tag', tag: 'improvements' }],
tags: [
{ kind: 'tag', tag: 'improvements' },
{ kind: 'tag', tag: 'category' },
{ kind: 'tag', tag: 'missing' },
],
},
isVoid: false,
nodes: [
@@ -197,6 +201,7 @@ describe('getDocumentSections', () => {
...context,
revision: {
tags: [
{ slug: 'category', label: 'Products', color: 'default', kind: 'category' },
{
slug: 'improvements',
label: 'Improvements',
@@ -143,6 +143,30 @@ describe('resolveStringContentRef', () => {
});
describe('resolveContentRef', () => {
it('does not resolve category or missing assignments as tag links', async () => {
const normal = { slug: 'constructor', label: 'Constructor', color: 'default' };
const category = {
slug: 'products',
label: 'Products',
color: 'default',
kind: 'category',
};
const context = {
space: { id: 'local' },
revision: { tags: [normal, category] },
linker: createLinker({
host: 'docs.example.com',
spaceBasePath: '/',
siteBasePath: '/',
}),
} as unknown as GitBookAnyContext;
expect(await resolveContentRef({ kind: 'tag', tag: 'products' }, context)).toBeNull();
expect(await resolveContentRef({ kind: 'tag', tag: 'missing' }, context)).toBeNull();
expect(
await resolveContentRef({ kind: 'tag', tag: 'constructor', space: 'local' }, context)
).toMatchObject({ text: 'Constructor' });
});
it("resolves a page in a different space using that space's page data, not the current context page", async () => {
const sharedPageId = 'page-shared';
+4 -2
View File
@@ -8,10 +8,12 @@ export function getRevisionTags(revision: Revision | undefined): RevisionTag[] {
}
/**
* Resolve a tag slug to its full RevisionTag.
* Resolve an assignment to a normal tag, ignoring categories and missing definitions.
*/
export function resolveTag(slug: string, revisionTags: RevisionTag[]): RevisionTag | undefined {
return revisionTags.find((t) => t.slug === slug);
return revisionTags.find(
(tag) => tag.slug === slug && !('kind' in tag && tag.kind === 'category')
);
}
/**
+43 -3
View File
@@ -1,7 +1,13 @@
import { describe, expect, it } from 'bun:test';
import type { JSONDocument, Revision } from '@gitbook/api';
import {
DocumentTextColor,
type JSONDocument,
type Revision,
type RevisionTag,
} from '@gitbook/api';
import { getRevisionTags, resolveBlockTags, resolveTag } from './tags';
import {
UPDATES_TAG_FILTER_CAP,
getDocumentFilterableTags,
@@ -9,6 +15,40 @@ import {
} from './updates';
describe('getDocumentFilterableTags', () => {
it('ignores category and deleted references without removing their stored assignments', () => {
const document = createUpdatesDocument([['category', 'constructor', 'missing']]);
const category = { ...createTag('category', 'Products'), kind: 'category' };
const normal = createTag('constructor', 'Constructor');
const revision = { tags: [category, normal] } as unknown as Revision;
const before = JSON.stringify(document);
expect(getDocumentFilterableTags(document, revision).map((tag) => tag.slug)).toEqual([
'constructor',
]);
expect(resolveTag('category', revision.tags)).toBeUndefined();
expect(resolveTag('missing', revision.tags)).toBeUndefined();
expect(resolveTag('constructor', revision.tags)).toEqual(normal);
expect(getRevisionTags(revision)).toEqual([category, normal]);
expect(JSON.stringify(document)).toBe(before);
});
it('rejects category assignments even when definitions are passed directly to the resolver', () => {
const normal = createTag('beta', 'Beta');
const tags = [
{ ...createTag('products', 'Products'), kind: 'category' },
normal,
] satisfies (RevisionTag & { kind?: 'category' })[];
expect(
resolveBlockTags(
[
{ kind: 'tag', tag: 'products' },
{ kind: 'tag', tag: 'beta' },
{ kind: 'tag', tag: 'missing' },
],
tags
)
).toEqual([normal]);
});
it('returns unique update tags in document order', () => {
const document = createUpdatesDocument([
['improvements', 'fixes'],
@@ -77,11 +117,11 @@ function createUpdatesDocument(entryTags: string[][]): JSONDocument {
};
}
function createTag(slug: string, label: string) {
function createTag(slug: string, label: string): RevisionTag {
return {
slug,
label,
color: 'default',
color: DocumentTextColor.Default,
icon: undefined,
};
}