@glossarist/concept-browser 0.2.11 → 0.2.13
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.
- package/package.json +1 -1
- package/src/__tests__/math.test.ts +11 -0
- package/src/utils/math.ts +7 -34
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glossarist/concept-browser",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.13",
|
|
4
4
|
"description": "Vue SPA for browsing Glossarist terminology datasets with cross-reference resolution, graph visualization, and multi-language support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -19,6 +19,13 @@ describe('renderMath', () => {
|
|
|
19
19
|
expect(result).toContain('math-bold');
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
+
it('renders latexmath:[...] with nested brackets', () => {
|
|
23
|
+
const result = renderMath('coords latexmath:[[u_0, u_1] \\leq 1.0] here');
|
|
24
|
+
expect(result).toContain('math-inline');
|
|
25
|
+
expect(result).toContain('katex');
|
|
26
|
+
expect(result).not.toContain('latexmath:');
|
|
27
|
+
});
|
|
28
|
+
|
|
22
29
|
it('converts bullet lines to <ul><li>', () => {
|
|
23
30
|
const result = renderMath('* first item\n\n* second item');
|
|
24
31
|
expect(result).toContain('<ul class="concept-list">');
|
|
@@ -110,6 +117,10 @@ describe('cleanContent', () => {
|
|
|
110
117
|
expect(cleanContent('value *stem:[x]* here')).toBe('value x here');
|
|
111
118
|
});
|
|
112
119
|
|
|
120
|
+
it('strips latexmath:[...] with nested brackets', () => {
|
|
121
|
+
expect(cleanContent('coords latexmath:[[u_0, u_1] \\leq 1.0] end')).toBe('coords [u_0, u_1] \\leq 1.0 end');
|
|
122
|
+
});
|
|
123
|
+
|
|
113
124
|
it('strips *text* to plain text', () => {
|
|
114
125
|
expect(cleanContent('some *italic* text')).toBe('some italic text');
|
|
115
126
|
});
|
package/src/utils/math.ts
CHANGED
|
@@ -10,12 +10,7 @@ export interface RenderOptions {
|
|
|
10
10
|
figResolver?: FigResolver;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
/**
|
|
14
|
-
* Convert `* item` lines into <ul><li> blocks.
|
|
15
|
-
* Also handles `1)` and `1.` numbered items into ordered lists.
|
|
16
|
-
*/
|
|
17
13
|
function convertLists(text: string): string {
|
|
18
|
-
// Unordered: * item (separated by \n or \n\n)
|
|
19
14
|
let result = text.replace(/(?:^|\n)((?:[ \t]*\* [^\n]+)(?:\n[ \t]*\* [^\n]+)*)/g, (_, block) => {
|
|
20
15
|
if (/^\*stem:\[/.test(block.trimStart())) return _;
|
|
21
16
|
const items: string[] = [];
|
|
@@ -29,7 +24,6 @@ function convertLists(text: string): string {
|
|
|
29
24
|
return `\n<ul class="concept-list">${lis}</ul>`;
|
|
30
25
|
});
|
|
31
26
|
|
|
32
|
-
// Ordered: 1) item or 1. item (numbered items)
|
|
33
27
|
result = result.replace(/(?:^|\n)((?:[ \t]*\d+[).][ \t]+[^\n]+)(?:\n[ \t]*\d+[).][ \t]+[^\n]+)*)/g, (_, block) => {
|
|
34
28
|
const items: string[] = [];
|
|
35
29
|
const re = /[ \t]*\d+[).][ \t]+([^\n]+)/g;
|
|
@@ -45,10 +39,6 @@ function convertLists(text: string): string {
|
|
|
45
39
|
return result;
|
|
46
40
|
}
|
|
47
41
|
|
|
48
|
-
/**
|
|
49
|
-
* Replace `prefix:[content]` where content may contain nested brackets.
|
|
50
|
-
* Handles `*prefix:[content]*` (bold) too.
|
|
51
|
-
*/
|
|
52
42
|
function replaceBracketed(
|
|
53
43
|
text: string,
|
|
54
44
|
prefix: string,
|
|
@@ -58,11 +48,8 @@ function replaceBracketed(
|
|
|
58
48
|
let i = 0;
|
|
59
49
|
const boldPrefix = '*' + prefix;
|
|
60
50
|
while (i < text.length) {
|
|
61
|
-
// Check for bold variant: *prefix:[...]
|
|
62
51
|
if (text.startsWith(boldPrefix + '[', i)) {
|
|
63
|
-
|
|
64
|
-
i += boldPrefix.length + 1; // skip *prefix:[
|
|
65
|
-
const depth = 1;
|
|
52
|
+
i += boldPrefix.length + 1;
|
|
66
53
|
let j = i;
|
|
67
54
|
let d = 1;
|
|
68
55
|
while (j < text.length && d > 0) {
|
|
@@ -71,13 +58,11 @@ function replaceBracketed(
|
|
|
71
58
|
j++;
|
|
72
59
|
}
|
|
73
60
|
const content = text.slice(i, j - 1);
|
|
74
|
-
// Check for closing *
|
|
75
61
|
let end = j;
|
|
76
62
|
if (end < text.length && text[end] === '*') end++;
|
|
77
63
|
result += render(content, true);
|
|
78
64
|
i = end;
|
|
79
65
|
}
|
|
80
|
-
// Check for normal variant: prefix:[...]
|
|
81
66
|
else if (text.startsWith(prefix + '[', i)) {
|
|
82
67
|
i += prefix.length + 1;
|
|
83
68
|
let j = i;
|
|
@@ -98,10 +83,6 @@ function replaceBracketed(
|
|
|
98
83
|
return result;
|
|
99
84
|
}
|
|
100
85
|
|
|
101
|
-
/**
|
|
102
|
-
* Render stem:[...] math notation to KaTeX HTML.
|
|
103
|
-
* Also handles cross-reference inline patterns (URN refs, bibliography, figures).
|
|
104
|
-
*/
|
|
105
86
|
export function renderMath(text: string, xrefResolverOrOpts?: XrefResolver | RenderOptions): string {
|
|
106
87
|
if (!text) return '';
|
|
107
88
|
let result = text;
|
|
@@ -118,7 +99,6 @@ export function renderMath(text: string, xrefResolverOrOpts?: XrefResolver | Ren
|
|
|
118
99
|
result = result.replace(/\*([^*]+)\*/g, '<em>$1</em>');
|
|
119
100
|
result = result.replace(/~([^~]+)~/g, '<sub>$1</sub>');
|
|
120
101
|
|
|
121
|
-
// Handle AsciiDoc bibliography xrefs: <<ref_XX,title>>
|
|
122
102
|
result = result.replace(/<<([^,>]+),([^>]+)>>/g, (_, refId, title) => {
|
|
123
103
|
if (opts.bibResolver) {
|
|
124
104
|
return opts.bibResolver(refId.trim(), title.trim());
|
|
@@ -126,7 +106,6 @@ export function renderMath(text: string, xrefResolverOrOpts?: XrefResolver | Ren
|
|
|
126
106
|
return `<span class="bib-ref">${escapeHtml(title.trim())}</span>`;
|
|
127
107
|
});
|
|
128
108
|
|
|
129
|
-
// Handle AsciiDoc figure xrefs: <<fig_XX>>
|
|
130
109
|
result = result.replace(/<<(fig_[^>]+)>>/g, (_, figId) => {
|
|
131
110
|
if (opts.figResolver) {
|
|
132
111
|
return opts.figResolver(figId.trim());
|
|
@@ -134,25 +113,22 @@ export function renderMath(text: string, xrefResolverOrOpts?: XrefResolver | Ren
|
|
|
134
113
|
return `<span class="fig-ref">${escapeHtml(figId.trim())}</span>`;
|
|
135
114
|
});
|
|
136
115
|
|
|
137
|
-
// Handle URN inline refs: {{urn:...,term[,displayText]}} (double-braced)
|
|
138
116
|
result = result.replace(/\{\{(urn:[^,}]+),([^,}]+)(?:,([^}]+))?\}\}/g, (_, uri, term, display) => {
|
|
139
|
-
const
|
|
117
|
+
const t = (display || term).trim();
|
|
140
118
|
if (opts.xrefResolver) {
|
|
141
|
-
return opts.xrefResolver(uri,
|
|
119
|
+
return opts.xrefResolver(uri, t);
|
|
142
120
|
}
|
|
143
|
-
return
|
|
121
|
+
return t;
|
|
144
122
|
});
|
|
145
123
|
|
|
146
|
-
// Handle URN inline refs: {urn:...,term[,displayText]} (single-braced)
|
|
147
124
|
result = result.replace(/\{(urn:[^,}]+),([^,}]+)(?:,([^}]+))?\}/g, (_, uri, term, display) => {
|
|
148
|
-
const
|
|
125
|
+
const t = (display || term).trim();
|
|
149
126
|
if (opts.xrefResolver) {
|
|
150
|
-
return opts.xrefResolver(uri,
|
|
127
|
+
return opts.xrefResolver(uri, t);
|
|
151
128
|
}
|
|
152
|
-
return
|
|
129
|
+
return t;
|
|
153
130
|
});
|
|
154
131
|
|
|
155
|
-
// Handle any remaining {{...}} refs (fallback: show term before comma)
|
|
156
132
|
result = result.replace(/\{\{([^,}]+)(?:,\s*[^}]+)?\}\}/g, '$1');
|
|
157
133
|
|
|
158
134
|
return result;
|
|
@@ -178,9 +154,6 @@ function escapeHtml(text: string): string {
|
|
|
178
154
|
.replace(/>/g, '>');
|
|
179
155
|
}
|
|
180
156
|
|
|
181
|
-
/**
|
|
182
|
-
* Clean content for plain text display (no math rendering).
|
|
183
|
-
*/
|
|
184
157
|
export function cleanContent(text: string): string {
|
|
185
158
|
if (!text) return '';
|
|
186
159
|
let result = text
|