@abreen/tada 1.5.1 → 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 (40) hide show
  1. package/package.json +3 -2
  2. package/bin/validators.test.ts +0 -205
  3. package/build/build-manifest.test.ts +0 -369
  4. package/build/code.test.ts +0 -272
  5. package/build/colors.test.ts +0 -66
  6. package/build/globals.test.ts +0 -100
  7. package/build/json-schema.test.ts +0 -57
  8. package/build/log.test.ts +0 -117
  9. package/build/markdown-plugins.test.ts +0 -456
  10. package/build/pagefind.test.ts +0 -192
  11. package/build/pdf-text.test.ts +0 -52
  12. package/build/reachability.test.ts +0 -80
  13. package/build/serve.test.ts +0 -59
  14. package/build/toc-plugin.test.ts +0 -120
  15. package/build/utils/content-files.test.ts +0 -56
  16. package/build/utils/derive-theme.test.ts +0 -111
  17. package/build/utils/file-types.test.ts +0 -79
  18. package/build/utils/front-matter.test.ts +0 -77
  19. package/build/utils/include.test.ts +0 -117
  20. package/build/utils/paths.test.ts +0 -91
  21. package/build/utils/trace-layout.test.ts +0 -570
  22. package/build/utils/trace-svg.test.ts +0 -425
  23. package/build/utils/trace.test.ts +0 -169
  24. package/build/validate-config-links.test.ts +0 -239
  25. package/build/validate-internal-links-plugin.test.ts +0 -134
  26. package/build/watch-reachability-state.test.ts +0 -198
  27. package/src/anchor/index.test.ts +0 -64
  28. package/src/code/index.test.ts +0 -71
  29. package/src/header/index.test.ts +0 -89
  30. package/src/navigate/eligible.test.ts +0 -101
  31. package/src/navigate/index.test.ts +0 -82
  32. package/src/navigate/lifecycle.test.ts +0 -26
  33. package/src/print/index.test.ts +0 -71
  34. package/src/question/index.test.ts +0 -82
  35. package/src/search/index.test.ts +0 -203
  36. package/src/timezone/index.test.ts +0 -400
  37. package/src/toc/index.test.ts +0 -237
  38. package/src/top/index.test.ts +0 -46
  39. package/src/trace/index.test.ts +0 -554
  40. package/src/util.test.ts +0 -135
@@ -1,272 +0,0 @@
1
- import { describe, expect, test, beforeAll } from 'bun:test';
2
- import { initHighlighter } from './utils/shiki-highlighter';
3
- import {
4
- renderCodeWithComments,
5
- extractJavaMethodToc,
6
- rewriteProseLinks,
7
- } from './utils/code';
8
- import type { SiteVariables } from './types';
9
-
10
- beforeAll(async () => {
11
- await initHighlighter(['java', 'text', 'plaintext']);
12
- });
13
-
14
- describe('extractJavaMethodToc', () => {
15
- test('returns methods from a regular class', () => {
16
- const toc = extractJavaMethodToc(`
17
- public class Foo {
18
- public void foo() {}
19
- public int bar(int x) { return x; }
20
- }
21
- `);
22
- expect(toc).toEqual([
23
- { kind: 'method', label: 'Method', name: 'foo()', line: 3 },
24
- { kind: 'method', label: 'Method', name: 'bar(x)', line: 4 },
25
- ]);
26
- });
27
-
28
- test('returns top-level methods from a compact source file', () => {
29
- const toc = extractJavaMethodToc(`
30
- void hello() {
31
- System.out.println("Hello");
32
- }
33
-
34
- void main() {
35
- hello();
36
- }
37
- `);
38
- expect(toc).toEqual([
39
- { kind: 'method', label: 'Method', name: 'hello()', line: 2 },
40
- { kind: 'method', label: 'Method', name: 'main()', line: 6 },
41
- ]);
42
- });
43
-
44
- test('returns empty array when class has no methods or fields', () => {
45
- const toc = extractJavaMethodToc(`
46
- public class Empty {
47
- }
48
- `);
49
- expect(toc).toEqual([]);
50
- });
51
-
52
- test('returns constructor from a class', () => {
53
- const toc = extractJavaMethodToc(`
54
- public class Point {
55
- public Point(int x) {}
56
- }
57
- `);
58
- expect(toc).toEqual([
59
- { kind: 'constructor', label: 'Constructor', name: 'Point(x)', line: 3 },
60
- ]);
61
- });
62
-
63
- test('excludes methods on inner classes', () => {
64
- const toc = extractJavaMethodToc(`
65
- public class Outer {
66
- public void outerMethod() {}
67
- static class Inner {
68
- public void innerMethod() {}
69
- }
70
- }
71
- `);
72
- expect(toc.map(e => e.name)).toEqual(['outerMethod()']);
73
- });
74
-
75
- test('returns default method from an interface', () => {
76
- const toc = extractJavaMethodToc(`
77
- public interface Greeter {
78
- default String greet(String name) { return "Hello, " + name; }
79
- }
80
- `);
81
- expect(toc).toEqual([
82
- { kind: 'method', label: 'Method', name: 'greet(name)', line: 3 },
83
- ]);
84
- });
85
-
86
- test('returns fields from a class with type but not access modifier', () => {
87
- const toc = extractJavaMethodToc(`
88
- public class Counter {
89
- private int count;
90
- public String label;
91
- }
92
- `);
93
- expect(toc.map(e => e.name)).toEqual(['int count', 'String label']);
94
- });
95
-
96
- test('returns one entry per variable in a multi-variable declaration', () => {
97
- const toc = extractJavaMethodToc(`
98
- public class Coords {
99
- int x, y;
100
- }
101
- `);
102
- expect(toc.map(e => e.name)).toEqual(['int x', 'int y']);
103
- });
104
-
105
- test('returns array type field', () => {
106
- const toc = extractJavaMethodToc(`
107
- public class Arr {
108
- int[] values;
109
- }
110
- `);
111
- expect(toc).toEqual([
112
- { kind: 'field', label: 'Field', name: 'int[] values', line: 3 },
113
- ]);
114
- });
115
-
116
- test('returns generic type field', () => {
117
- const toc = extractJavaMethodToc(`
118
- public class Container {
119
- List<String> items;
120
- }
121
- `);
122
- expect(toc).toEqual([
123
- { kind: 'field', label: 'Field', name: 'List<String> items', line: 3 },
124
- ]);
125
- });
126
-
127
- test('returns interface constant', () => {
128
- const toc = extractJavaMethodToc(`
129
- public interface Config {
130
- int TIMEOUT = 30;
131
- }
132
- `);
133
- expect(toc).toEqual([
134
- { kind: 'field', label: 'Field', name: 'int TIMEOUT', line: 3 },
135
- ]);
136
- });
137
-
138
- test('returns abstract interface methods (no body)', () => {
139
- const toc = extractJavaMethodToc(`
140
- public interface Greeter {
141
- String greet(String name);
142
- }
143
- `);
144
- expect(toc).toEqual([
145
- { kind: 'method', label: 'Method', name: 'greet(name)', line: 3 },
146
- ]);
147
- });
148
- });
149
-
150
- describe('renderCodeWithComments', () => {
151
- test('renders build-time line rows for code segments', () => {
152
- const html = renderCodeWithComments('alpha\n\nbeta\n', 'java', {
153
- base: '',
154
- basePath: '/',
155
- internalDomains: [],
156
- title: 'Test',
157
- titlePostfix: ' - Test',
158
- themeColor: 'steelblue',
159
- defaultTimeZone: 'America/New_York',
160
- } as SiteVariables);
161
-
162
- expect(html).toContain('<span class="code-row">');
163
- expect(html).toContain('id="L1" href="#L1"');
164
- expect(html).toContain('id="L2" href="#L2"');
165
- expect(html).toContain('id="L3" href="#L3"');
166
- expect(html).not.toContain('id="L4" href="#L4"');
167
- expect(html).toContain('<code class="shiki language-java">');
168
- });
169
-
170
- test('data-prose-source contains rewritten links when pageDirPath is provided', () => {
171
- const source = '/// See [rect](./rect.py)\npublic class Foo {}\n';
172
- const html = renderCodeWithComments(
173
- source,
174
- 'java',
175
- {
176
- base: 'https://example.edu',
177
- basePath: '/course',
178
- codeLanguages: { java: 'java', py: 'python' },
179
- internalDomains: [],
180
- title: 'Test',
181
- titlePostfix: ' - Test',
182
- themeColor: 'steelblue',
183
- defaultTimeZone: 'America/New_York',
184
- } as SiteVariables,
185
- 'lectures/01',
186
- );
187
-
188
- expect(html).toContain(
189
- 'https://example.edu/course/lectures/01/rect.py.html',
190
- );
191
- });
192
- });
193
-
194
- describe('rewriteProseLinks', () => {
195
- const siteVariables = {
196
- base: 'https://example.edu',
197
- basePath: '/course',
198
- codeLanguages: { java: 'java', py: 'python' },
199
- internalDomains: [],
200
- title: 'Test',
201
- titlePostfix: ' - Test',
202
- themeColor: 'steelblue',
203
- defaultTimeZone: 'America/New_York',
204
- } as SiteVariables;
205
-
206
- test('rewrites relative link with base + basePath', () => {
207
- const lines = ['/// See [rectangle.py](./rectangle.py)'];
208
- const result = rewriteProseLinks(lines, siteVariables, 'lectures/01');
209
- expect(result[0]).toBe(
210
- '/// See [rectangle.py](https://example.edu/course/lectures/01/rectangle.py.html)',
211
- );
212
- });
213
-
214
- test('rewrites absolute link with base + basePath', () => {
215
- const lines = ['/// See [about](/about.html)'];
216
- const result = rewriteProseLinks(lines, siteVariables, 'lectures/01');
217
- expect(result[0]).toBe(
218
- '/// See [about](https://example.edu/course/about.html)',
219
- );
220
- });
221
-
222
- test('leaves external links unchanged', () => {
223
- const lines = ['/// See [Google](https://google.com)'];
224
- const result = rewriteProseLinks(lines, siteVariables, 'lectures/01');
225
- expect(result[0]).toBe('/// See [Google](https://google.com)');
226
- });
227
-
228
- test('leaves anchor links unchanged', () => {
229
- const lines = ['/// See [section](#overview)'];
230
- const result = rewriteProseLinks(lines, siteVariables, 'lectures/01');
231
- expect(result[0]).toBe('/// See [section](#overview)');
232
- });
233
-
234
- test('applies code extension rewriting', () => {
235
- const lines = ['/// See [App](./App.java)'];
236
- const result = rewriteProseLinks(lines, siteVariables, 'lectures/01');
237
- expect(result[0]).toBe(
238
- '/// See [App](https://example.edu/course/lectures/01/App.java.html)',
239
- );
240
- });
241
-
242
- test('handles multiple links on one line', () => {
243
- const lines = ['/// See [a](./a.py) and [b](./b.java)'];
244
- const result = rewriteProseLinks(lines, siteVariables, 'lectures/01');
245
- expect(result[0]).toBe(
246
- '/// See [a](https://example.edu/course/lectures/01/a.py.html) and [b](https://example.edu/course/lectures/01/b.java.html)',
247
- );
248
- });
249
-
250
- test('does not rewrite non-comment lines', () => {
251
- const lines = ['String s = "[link](./file.py)";'];
252
- const result = rewriteProseLinks(lines, siteVariables, 'lectures/01');
253
- expect(result[0]).toBe('String s = "[link](./file.py)";');
254
- });
255
-
256
- test('preserves query string and fragment', () => {
257
- const lines = ['/// See [code](./App.java?view=1#L5)'];
258
- const result = rewriteProseLinks(lines, siteVariables, 'lectures/01');
259
- expect(result[0]).toBe(
260
- '/// See [code](https://example.edu/course/lectures/01/App.java.html?view=1#L5)',
261
- );
262
- });
263
-
264
- test('works with root basePath', () => {
265
- const vars = { ...siteVariables, basePath: '/' } as SiteVariables;
266
- const lines = ['/// See [rect](./rect.py)'];
267
- const result = rewriteProseLinks(lines, vars, 'lectures/01');
268
- expect(result[0]).toBe(
269
- '/// See [rect](https://example.edu/lectures/01/rect.py.html)',
270
- );
271
- });
272
- });
@@ -1,66 +0,0 @@
1
- import { describe, expect, test } from 'bun:test';
2
- import { R, G, B, Y, L, P, I, Ri, Gi, Yi, Li } from './colors';
3
-
4
- describe('color tag functions', () => {
5
- test('R wraps text in red', () => {
6
- const result = R`hello`;
7
- expect(result).toContain('hello');
8
- expect(typeof result).toBe('string');
9
- });
10
-
11
- test('G wraps text in green', () => {
12
- const result = G`hello`;
13
- expect(result).toContain('hello');
14
- });
15
-
16
- test('B wraps text in blue', () => {
17
- const result = B`hello`;
18
- expect(result).toContain('hello');
19
- });
20
-
21
- test('Y wraps text in yellow', () => {
22
- const result = Y`hello`;
23
- expect(result).toContain('hello');
24
- });
25
-
26
- test('L wraps text in dim', () => {
27
- const result = L`hello`;
28
- expect(result).toContain('hello');
29
- });
30
-
31
- test('P wraps text in magenta', () => {
32
- const result = P`hello`;
33
- expect(result).toContain('hello');
34
- });
35
-
36
- test('I wraps text in italic bold', () => {
37
- const result = I`hello`;
38
- expect(result).toContain('hello');
39
- });
40
-
41
- test('Ri wraps text in inverse red', () => {
42
- const result = Ri`hello`;
43
- expect(result).toContain('hello');
44
- });
45
-
46
- test('Gi wraps text in inverse green', () => {
47
- const result = Gi`hello`;
48
- expect(result).toContain('hello');
49
- });
50
-
51
- test('Yi wraps text in inverse yellow', () => {
52
- const result = Yi`hello`;
53
- expect(result).toContain('hello');
54
- });
55
-
56
- test('Li wraps text in inverse dim', () => {
57
- const result = Li`hello`;
58
- expect(result).toContain('hello');
59
- });
60
-
61
- test('handles template interpolation', () => {
62
- const name = 'world';
63
- const result = R`hello ${name}`;
64
- expect(result).toContain('hello world');
65
- });
66
- });
@@ -1,100 +0,0 @@
1
- import { describe, expect, test } from 'bun:test';
2
- import createGlobals from './globals';
3
- import type { SiteVariables } from './types';
4
-
5
- const baseSite: SiteVariables = {
6
- base: 'http://localhost:8080',
7
- basePath: '/',
8
- title: 'Test',
9
- titlePostfix: ' - Test',
10
- themeColor: 'hsl(195 70% 40%)',
11
- defaultTimeZone: 'America/New_York',
12
- };
13
-
14
- function makeGlobals(subPath = 'index', site: Partial<SiteVariables> = {}) {
15
- return createGlobals({}, { ...baseSite, ...site }, subPath);
16
- }
17
-
18
- describe('createGlobals', () => {
19
- test('isHomePage is true when subPath is "index"', () => {
20
- expect(makeGlobals('index').isHomePage).toBe(true);
21
- });
22
-
23
- test('isHomePage is false for other paths', () => {
24
- expect(makeGlobals('about').isHomePage).toBe(false);
25
- expect(makeGlobals('docs/guide').isHomePage).toBe(false);
26
- });
27
-
28
- test('cx is an alias for classNames', () => {
29
- const g = makeGlobals();
30
- expect(g.cx).toBe(g.classNames);
31
- });
32
-
33
- test('renderTimeZoneChooser includes hidden disabled select, inline script, and noscript', () => {
34
- const g = makeGlobals('index', { defaultTimeZone: 'America/New_York' });
35
- const html = g.renderTimeZoneChooser();
36
- expect(html).toContain('<select class="time-zone" hidden disabled>');
37
- expect(html).toContain('<noscript>Times shown in ET.</noscript>');
38
- });
39
- });
40
-
41
- describe('isoDate', () => {
42
- test('converts date string to ISO date', () => {
43
- const g = makeGlobals();
44
- expect(g.isoDate('2025-06-15')).toBe('2025-06-15');
45
- });
46
-
47
- test('converts full datetime to date only', () => {
48
- const g = makeGlobals();
49
- expect(g.isoDate('2025-06-15T12:30:00Z')).toBe('2025-06-15');
50
- });
51
-
52
- test('returns null for null/undefined/empty', () => {
53
- const g = makeGlobals();
54
- expect(g.isoDate(null)).toBe(null);
55
- expect(g.isoDate(undefined)).toBe(null);
56
- expect(g.isoDate('')).toBe(null);
57
- });
58
- });
59
-
60
- describe('readableDate', () => {
61
- test('formats date as Month Day, Year', () => {
62
- const g = makeGlobals();
63
- expect(g.readableDate('2025-01-15T00:00:00Z')).toBe('January 15, 2025');
64
- });
65
-
66
- test('strips leading zeros from day and month', () => {
67
- const g = makeGlobals();
68
- expect(g.readableDate('2025-03-05T00:00:00Z')).toBe('March 5, 2025');
69
- });
70
-
71
- test('handles Date objects', () => {
72
- const g = makeGlobals();
73
- const result = g.readableDate(new Date('2025-12-25T00:00:00Z'));
74
- expect(result).toBe('December 25, 2025');
75
- });
76
-
77
- test('returns empty string for null/undefined/empty', () => {
78
- const g = makeGlobals();
79
- expect(g.readableDate(null)).toBe('');
80
- expect(g.readableDate(undefined)).toBe('');
81
- expect(g.readableDate('')).toBe('');
82
- });
83
- });
84
-
85
- describe('classNames', () => {
86
- test('returns truthy keys joined by space', () => {
87
- const g = makeGlobals();
88
- expect(g.classNames({ foo: true, bar: false, baz: 1 })).toBe('foo baz');
89
- });
90
-
91
- test('returns empty string when all falsy', () => {
92
- const g = makeGlobals();
93
- expect(g.classNames({ a: false, b: 0, c: '' })).toBe('');
94
- });
95
-
96
- test('returns empty string for empty object', () => {
97
- const g = makeGlobals();
98
- expect(g.classNames({})).toBe('');
99
- });
100
- });
@@ -1,57 +0,0 @@
1
- import { describe, expect, test } from 'bun:test';
2
- import { compile, doValidation } from './json-schema';
3
-
4
- const schema = {
5
- type: 'object',
6
- properties: { name: { type: 'string' }, age: { type: 'number' } },
7
- required: ['name'],
8
- additionalProperties: false,
9
- };
10
-
11
- describe('compile', () => {
12
- test('returns a validate function', () => {
13
- const validator = compile(schema);
14
- expect(typeof validator).toBe('function');
15
- });
16
- });
17
-
18
- describe('doValidation', () => {
19
- test('does not throw for valid input', () => {
20
- const validator = compile(schema);
21
- expect(() =>
22
- doValidation(validator, { name: 'Alice' }, 'test.json'),
23
- ).not.toThrow();
24
- });
25
-
26
- test('does not throw when optional fields are present', () => {
27
- const validator = compile(schema);
28
- expect(() =>
29
- doValidation(validator, { name: 'Alice', age: 30 }, 'test.json'),
30
- ).not.toThrow();
31
- });
32
-
33
- test('throws when required field is missing', () => {
34
- const validator = compile(schema);
35
- expect(() => doValidation(validator, {}, 'test.json')).toThrow(
36
- 'test.json failed validation',
37
- );
38
- });
39
-
40
- test('throws with additionalProperties message', () => {
41
- const validator = compile(schema);
42
- expect(() =>
43
- doValidation(validator, { name: 'Alice', extra: true }, 'test.json'),
44
- ).toThrow('unknown property "extra"');
45
- });
46
-
47
- test('throws with field path in error', () => {
48
- const nestedSchema = {
49
- type: 'object',
50
- properties: { name: { type: 'string' } },
51
- };
52
- const validator = compile(nestedSchema);
53
- expect(() => doValidation(validator, { name: 123 }, 'data.json')).toThrow(
54
- 'data.json failed validation',
55
- );
56
- });
57
- });
package/build/log.test.ts DELETED
@@ -1,117 +0,0 @@
1
- import { describe, expect, test } from 'bun:test';
2
- import { makeLogger, getFlair } from './log';
3
-
4
- function captureOutput(fn: () => void): { stdout: string; stderr: string } {
5
- let stdout = '';
6
- let stderr = '';
7
- const origStdout = process.stdout.write;
8
- const origStderr = process.stderr.write;
9
- process.stdout.write = ((chunk: string) => {
10
- stdout += chunk;
11
- return true;
12
- }) as typeof process.stdout.write;
13
- process.stderr.write = ((chunk: string) => {
14
- stderr += chunk;
15
- return true;
16
- }) as typeof process.stderr.write;
17
- try {
18
- fn();
19
- } finally {
20
- process.stdout.write = origStdout;
21
- process.stderr.write = origStderr;
22
- }
23
- return { stdout, stderr };
24
- }
25
-
26
- describe('makeLogger', () => {
27
- test('creates a logger with default info level', () => {
28
- const log = makeLogger('test');
29
- expect(log.minLogLevel).toBe('info');
30
- });
31
-
32
- test('throws on invalid log level', () => {
33
- expect(() => makeLogger('test', 'verbose')).toThrow('Invalid log level');
34
- });
35
-
36
- test('info writes to stdout', () => {
37
- const log = makeLogger('test', 'info');
38
- const { stdout } = captureOutput(() => log.info`hello world`);
39
- expect(stdout).toContain('hello world');
40
- });
41
-
42
- test('debug is suppressed at info level', () => {
43
- const log = makeLogger('test', 'info');
44
- const { stderr } = captureOutput(() => log.debug`should not appear`);
45
- expect(stderr).toBe('');
46
- });
47
-
48
- test('debug appears at debug level', () => {
49
- const log = makeLogger('test', 'debug');
50
- const { stderr } = captureOutput(() => log.debug`visible`);
51
- expect(stderr).toContain('visible');
52
- });
53
-
54
- test('warn writes to stdout', () => {
55
- const log = makeLogger('test', 'warn');
56
- const { stdout } = captureOutput(() => log.warn`caution`);
57
- expect(stdout).toContain('caution');
58
- });
59
-
60
- test('error writes to stdout', () => {
61
- const log = makeLogger('test', 'error');
62
- const { stdout } = captureOutput(() => log.error`failure`);
63
- expect(stdout).toContain('failure');
64
- });
65
-
66
- test('event always writes', () => {
67
- const log = makeLogger('test', 'error');
68
- const { stdout } = captureOutput(() => log.event`done`);
69
- expect(stdout).toContain('done');
70
- });
71
-
72
- test('followup writes strings', () => {
73
- const log = makeLogger('test');
74
- const { stdout } = captureOutput(() => log.followup(['line1', 'line2']));
75
- expect(stdout).toContain('line1');
76
- expect(stdout).toContain('line2');
77
- });
78
-
79
- test('setMinLogLevel changes filtering', () => {
80
- const log = makeLogger('test', 'info');
81
- log.setMinLogLevel('error');
82
- const { stdout } = captureOutput(() => log.info`suppressed`);
83
- expect(stdout).toBe('');
84
- });
85
-
86
- test('handles empty name', () => {
87
- const log = makeLogger('');
88
- expect(log.minLogLevel).toBe('info');
89
- });
90
-
91
- test('handles path-style name', () => {
92
- const log = makeLogger('/path/to/module.ts');
93
- const { stdout } = captureOutput(() => log.info`test`);
94
- expect(stdout).toContain('test');
95
- });
96
-
97
- test('handles file:// URL name', () => {
98
- const log = makeLogger('file:///path/to/module.ts');
99
- const { stdout } = captureOutput(() => log.info`test`);
100
- expect(stdout).toContain('test');
101
- });
102
-
103
- test('interpolates objects in template', () => {
104
- const log = makeLogger('test');
105
- const obj = { key: 'value' };
106
- const { stdout } = captureOutput(() => log.info`data: ${obj}`);
107
- expect(stdout).toContain('key');
108
- });
109
- });
110
-
111
- describe('getFlair', () => {
112
- test('returns a non-empty string with emoji', () => {
113
- const flair = getFlair();
114
- expect(flair.length).toBeGreaterThan(0);
115
- expect(flair).toContain('🎉');
116
- });
117
- });