@abreen/tada 1.5.0 → 1.5.2

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 (45) hide show
  1. package/build/generate-content-assets.ts +2 -2
  2. package/build/types.d.ts +1 -0
  3. package/build/utils/render.ts +5 -0
  4. package/build/utils/trace.ts +70 -22
  5. package/package.json +4 -3
  6. package/src/trace/index.ts +9 -1
  7. package/bin/validators.test.ts +0 -205
  8. package/build/build-manifest.test.ts +0 -369
  9. package/build/code.test.ts +0 -272
  10. package/build/colors.test.ts +0 -66
  11. package/build/globals.test.ts +0 -100
  12. package/build/json-schema.test.ts +0 -57
  13. package/build/log.test.ts +0 -117
  14. package/build/markdown-plugins.test.ts +0 -456
  15. package/build/pagefind.test.ts +0 -192
  16. package/build/pdf-text.test.ts +0 -52
  17. package/build/reachability.test.ts +0 -80
  18. package/build/serve.test.ts +0 -59
  19. package/build/toc-plugin.test.ts +0 -120
  20. package/build/utils/content-files.test.ts +0 -56
  21. package/build/utils/derive-theme.test.ts +0 -111
  22. package/build/utils/file-types.test.ts +0 -79
  23. package/build/utils/front-matter.test.ts +0 -77
  24. package/build/utils/include.test.ts +0 -117
  25. package/build/utils/paths.test.ts +0 -91
  26. package/build/utils/trace-layout.test.ts +0 -570
  27. package/build/utils/trace-svg.test.ts +0 -425
  28. package/build/utils/trace.test.ts +0 -169
  29. package/build/validate-config-links.test.ts +0 -239
  30. package/build/validate-internal-links-plugin.test.ts +0 -134
  31. package/build/watch-reachability-state.test.ts +0 -198
  32. package/src/anchor/index.test.ts +0 -64
  33. package/src/code/index.test.ts +0 -71
  34. package/src/header/index.test.ts +0 -89
  35. package/src/navigate/eligible.test.ts +0 -101
  36. package/src/navigate/index.test.ts +0 -82
  37. package/src/navigate/lifecycle.test.ts +0 -26
  38. package/src/print/index.test.ts +0 -71
  39. package/src/question/index.test.ts +0 -82
  40. package/src/search/index.test.ts +0 -203
  41. package/src/timezone/index.test.ts +0 -400
  42. package/src/toc/index.test.ts +0 -237
  43. package/src/top/index.test.ts +0 -46
  44. package/src/trace/index.test.ts +0 -528
  45. package/src/util.test.ts +0 -135
@@ -1,237 +0,0 @@
1
- import { describe, expect, test } from 'bun:test';
2
- import { JSDOM } from 'jsdom';
3
- import mount, {
4
- getHighlightIndexes,
5
- headingToTableItem,
6
- alertToTableItem,
7
- switchCurrent,
8
- type Heading,
9
- type Alert,
10
- type Dinkus,
11
- } from './index';
12
-
13
- function dom(html: string) {
14
- return new JSDOM(`<body>${html}</body>`);
15
- }
16
-
17
- describe('getHighlightIndexes', () => {
18
- test('maps headings to their own index', () => {
19
- const items: Heading[] = [
20
- { level: '1', id: 'a', innerHtml: 'A' },
21
- { level: '2', id: 'b', innerHtml: 'B' },
22
- ];
23
- expect(getHighlightIndexes(items)).toEqual([0, 1]);
24
- });
25
-
26
- test('maps alerts to the preceding heading index', () => {
27
- const items: (Heading | Alert)[] = [
28
- { level: '1', id: 'a', innerHtml: 'A' },
29
- { type: 'warning', title: 'Watch out' },
30
- { level: '2', id: 'b', innerHtml: 'B' },
31
- ];
32
- expect(getHighlightIndexes(items)).toEqual([0, 0, 2]);
33
- });
34
-
35
- test('alert before any heading gets its own index', () => {
36
- const items: (Heading | Alert)[] = [
37
- { type: 'note', title: 'FYI' },
38
- { level: '1', id: 'a', innerHtml: 'A' },
39
- ];
40
- expect(getHighlightIndexes(items)).toEqual([0, 1]);
41
- });
42
-
43
- test('skips dinkus items entirely', () => {
44
- const items: (Heading | Dinkus)[] = [
45
- { level: '1', id: 'a', innerHtml: 'A' },
46
- { type: 'dinkus' },
47
- { level: '2', id: 'b', innerHtml: 'B' },
48
- ];
49
- expect(getHighlightIndexes(items)).toEqual([0, 1]);
50
- });
51
-
52
- test('returns empty array for empty input', () => {
53
- expect(getHighlightIndexes([])).toEqual([]);
54
- });
55
- });
56
-
57
- describe('headingToTableItem', () => {
58
- test('extracts level and innerHTML from a heading', () => {
59
- const { document } = dom('<h2 id="intro">Introduction</h2>').window;
60
- const el = document.querySelector('h2') as HTMLHeadingElement;
61
- const result = headingToTableItem(el);
62
- expect(result).toEqual({
63
- level: '2',
64
- id: 'intro',
65
- innerHtml: 'Introduction',
66
- });
67
- });
68
-
69
- test('separates subtitle from main text', () => {
70
- const { document } = dom(
71
- '<h3 id="s"><span class="heading-subtitle">v2</span>Setup</h3>',
72
- ).window;
73
- const el = document.querySelector('h3') as HTMLHeadingElement;
74
- const result = headingToTableItem(el);
75
- expect(result.level).toBe('3');
76
- expect(result.id).toBe('s');
77
- expect(result.innerHtml).toContain('Setup');
78
- expect(result.innerHtml).toContain('heading-subtitle');
79
- });
80
-
81
- test('uses innerHTML when no subtitle', () => {
82
- const { document } = dom('<h1 id="top"><em>Bold</em> title</h1>').window;
83
- const el = document.querySelector('h1') as HTMLHeadingElement;
84
- const result = headingToTableItem(el);
85
- expect(result.innerHtml).toBe('<em>Bold</em> title');
86
- });
87
- });
88
-
89
- describe('alertToTableItem', () => {
90
- test('returns warning alert with custom title', () => {
91
- const { document } = dom(
92
- '<div class="alert warning"><span class="title">Danger</span></div>',
93
- ).window;
94
- const el = document.querySelector('.alert') as HTMLElement;
95
- expect(alertToTableItem(el)).toEqual({ type: 'warning', title: 'Danger' });
96
- });
97
-
98
- test('returns note alert with default title', () => {
99
- const { document } = dom('<div class="alert note">Some note</div>').window;
100
- const el = document.querySelector('.alert') as HTMLElement;
101
- expect(alertToTableItem(el)).toEqual({ type: 'note', title: 'Note' });
102
- });
103
-
104
- test('returns default Warning title when no .title element', () => {
105
- const { document } = dom(
106
- '<div class="alert warning">Text only</div>',
107
- ).window;
108
- const el = document.querySelector('.alert') as HTMLElement;
109
- expect(alertToTableItem(el)).toEqual({ type: 'warning', title: 'Warning' });
110
- });
111
-
112
- test('returns null for non-warning/note alert types', () => {
113
- const { document } = dom('<div class="alert info">Some info</div>').window;
114
- const el = document.querySelector('.alert') as HTMLElement;
115
- expect(alertToTableItem(el)).toBeNull();
116
- });
117
- });
118
-
119
- describe('switchCurrent', () => {
120
- test('adds current class to new element', () => {
121
- const { document } = dom('<li>A</li><li>B</li>').window;
122
- const items = document.querySelectorAll('li');
123
- switchCurrent(null, items[0] as HTMLElement);
124
- expect(items[0].classList.contains('current')).toBe(true);
125
- });
126
-
127
- test('removes current from old and adds to new', () => {
128
- const { document } = dom('<li class="current">A</li><li>B</li>').window;
129
- const items = document.querySelectorAll('li');
130
- switchCurrent(items[0] as HTMLElement, items[1] as HTMLElement);
131
- expect(items[0].classList.contains('current')).toBe(false);
132
- expect(items[1].classList.contains('current')).toBe(true);
133
- });
134
- });
135
-
136
- describe('toc mount', () => {
137
- test('returns early when no nav.toc exists', () => {
138
- const win = dom('<div>No toc</div>').window;
139
- const cleanup = mount(win);
140
- expect(cleanup).toBeUndefined();
141
- });
142
-
143
- test('returns early when toc has no links', () => {
144
- const win = dom('<nav class="toc"><ol></ol></nav>').window;
145
- const cleanup = mount(win);
146
- expect(cleanup).toBeUndefined();
147
- });
148
-
149
- describe('code page', () => {
150
- function createCodePage(hash = '') {
151
- const html =
152
- '<nav class="toc"><ol>' +
153
- '<li><a href="#L1">main</a></li>' +
154
- '<li><a href="#L10">helper</a></li>' +
155
- '<li><a href="#L20">util</a></li>' +
156
- '</ol></nav>' +
157
- '<div class="body"></div>';
158
- return new JSDOM(`<body class="code">${html}</body>`, {
159
- url: `http://localhost/${hash}`,
160
- }).window;
161
- }
162
-
163
- test('highlights the matching toc entry for the current hash', () => {
164
- const win = createCodePage('#L10');
165
- mount(win);
166
-
167
- const items = win.document.querySelectorAll('nav.toc ol li');
168
- expect(items[1].classList.contains('current')).toBe(true);
169
- });
170
-
171
- test('highlights nearest entry when hash is between line ranges', () => {
172
- const win = createCodePage('#L15');
173
- mount(win);
174
-
175
- const items = win.document.querySelectorAll('nav.toc ol li');
176
- expect(items[1].classList.contains('current')).toBe(true);
177
- });
178
-
179
- test('parses range hashes like #L5-L10', () => {
180
- const win = createCodePage('#L5-L10');
181
- mount(win);
182
-
183
- const items = win.document.querySelectorAll('nav.toc ol li');
184
- expect(items[0].classList.contains('current')).toBe(true);
185
- });
186
-
187
- test('no current item when hash has no line number', () => {
188
- const win = createCodePage('');
189
- mount(win);
190
-
191
- const current = win.document.querySelector('nav.toc .current');
192
- expect(current).toBeNull();
193
- });
194
-
195
- test('cleanup removes hashchange listener', () => {
196
- const win = createCodePage('#L1');
197
- const cleanup = mount(win);
198
-
199
- expect(typeof cleanup).toBe('function');
200
- cleanup!();
201
- });
202
- });
203
-
204
- describe('regular page', () => {
205
- function createRegularPage() {
206
- const html =
207
- '<nav class="toc"><ol>' +
208
- '<li><a href="#intro">Introduction</a></li>' +
209
- '<li><a href="#setup">Setup</a></li>' +
210
- '</ol></nav>' +
211
- '<div class="body">' +
212
- '<h2 id="intro">Introduction</h2>' +
213
- '<p>Content</p>' +
214
- '<h2 id="setup">Setup</h2>' +
215
- '<p>More content</p>' +
216
- '</div>';
217
- return new JSDOM(`<body>${html}</body>`, { url: 'http://localhost/' })
218
- .window;
219
- }
220
-
221
- test('sets a current item on mount', () => {
222
- const win = createRegularPage();
223
- mount(win);
224
-
225
- const current = win.document.querySelector('nav.toc .current');
226
- expect(current).not.toBeNull();
227
- });
228
-
229
- test('cleanup removes scroll listener', () => {
230
- const win = createRegularPage();
231
- const cleanup = mount(win);
232
-
233
- expect(typeof cleanup).toBe('function');
234
- cleanup!();
235
- });
236
- });
237
- });
@@ -1,46 +0,0 @@
1
- import { describe, expect, test } from 'bun:test';
2
- import { JSDOM } from 'jsdom';
3
- import mount from './index';
4
-
5
- function create(html = '') {
6
- const dom = new JSDOM(`<body>${html}</body>`, { url: 'http://localhost/' });
7
- return dom.window;
8
- }
9
-
10
- describe('top', () => {
11
- test('creates a back-to-top link in the body', () => {
12
- const win = create();
13
- mount(win);
14
-
15
- const link = win.document.querySelector('a.button');
16
- expect(link).not.toBeNull();
17
- expect(link!.getAttribute('href')).toBe('#');
18
- });
19
-
20
- test('mounts link inside #to-top-container when present', () => {
21
- const win = create('<div id="to-top-container"></div>');
22
- mount(win);
23
-
24
- const container = win.document.getElementById('to-top-container')!;
25
- const link = container.querySelector('a.button');
26
- expect(link).not.toBeNull();
27
- });
28
-
29
- test('link starts hidden (no is-visible class)', () => {
30
- const win = create();
31
- mount(win);
32
-
33
- const link = win.document.querySelector('a.button')!;
34
- expect(link.classList.contains('is-visible')).toBe(false);
35
- expect(link.getAttribute('tabindex')).toBe('-1');
36
- });
37
-
38
- test('cleanup removes scroll listener', () => {
39
- const win = create();
40
- const cleanup = mount(win);
41
-
42
- expect(typeof cleanup).toBe('function');
43
- // Should not throw
44
- cleanup!();
45
- });
46
- });