@glossarist/concept-browser 0.2.12 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glossarist/concept-browser",
3
- "version": "0.2.12",
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,12 +19,12 @@
19
19
  "test:watch": "vitest"
20
20
  },
21
21
  "dependencies": {
22
- "@plurimath/plurimath": "^0.2.2",
23
22
  "@vitejs/plugin-vue": "^5.2.3",
24
23
  "autoprefixer": "^10.4.21",
25
24
  "d3": "^7.9.0",
26
25
  "glossarist": "^0.2.0",
27
26
  "js-yaml": "^4.1.0",
27
+ "katex": "^0.16.45",
28
28
  "pinia": "^2.3.1",
29
29
  "postcss": "^8.5.3",
30
30
  "tailwindcss": "^3.4.17",
@@ -1,22 +1,4 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
-
3
- // Mock @plurimath/plurimath for test environment
4
- vi.mock('@plurimath/plurimath', () => {
5
- return {
6
- default: class MockPlurimath {
7
- private data: string;
8
- private format: string;
9
- constructor(data: string, format: string) {
10
- this.data = data;
11
- this.format = format;
12
- }
13
- toMathml() {
14
- return `<math xmlns="http://www.w3.org/1998/Math/MathML"><mi>${this.data}</mi></math>`;
15
- }
16
- },
17
- };
18
- });
19
-
1
+ import { describe, it, expect } from 'vitest';
20
2
  import { renderMath, cleanContent } from '../utils/math';
21
3
 
22
4
  describe('renderMath', () => {
@@ -24,10 +6,10 @@ describe('renderMath', () => {
24
6
  expect(renderMath('hello world')).toBe('hello world');
25
7
  });
26
8
 
27
- it('renders stem:[x^2] to MathML span', () => {
9
+ it('renders stem:[x^2] to KaTeX span', () => {
28
10
  const result = renderMath('the value stem:[x^2]');
29
11
  expect(result).toContain('math-inline');
30
- expect(result).toContain('<math');
12
+ expect(result).toContain('katex');
31
13
  expect(result).not.toContain('math-bold');
32
14
  });
33
15
 
@@ -40,8 +22,7 @@ describe('renderMath', () => {
40
22
  it('renders latexmath:[...] with nested brackets', () => {
41
23
  const result = renderMath('coords latexmath:[[u_0, u_1] \\leq 1.0] here');
42
24
  expect(result).toContain('math-inline');
43
- expect(result).toContain('<math');
44
- expect(result).toContain('u_0');
25
+ expect(result).toContain('katex');
45
26
  expect(result).not.toContain('latexmath:');
46
27
  });
47
28
 
package/src/main.ts CHANGED
@@ -2,6 +2,7 @@ import { createApp } from 'vue';
2
2
  import { createPinia } from 'pinia';
3
3
  import App from './App.vue';
4
4
  import router from './router';
5
+ import 'katex/dist/katex.min.css';
5
6
  import './style.css';
6
7
 
7
8
  const app = createApp(App);
package/src/style.css CHANGED
@@ -158,16 +158,13 @@
158
158
  font-family: var(--font-body);
159
159
  }
160
160
 
161
- /* Math (Plurimath MathML output) */
162
- .math-inline {
163
- display: inline;
164
- }
165
- .math-inline math {
161
+ /* Math */
162
+ .math-inline .katex {
166
163
  font-size: 1.05em;
167
164
  }
168
- .math-bold math mi,
169
- .math-bold math mn,
170
- .math-bold math mo {
165
+ .math-bold .katex .mord,
166
+ .math-bold .katex .mbin,
167
+ .math-bold .katex .mrel {
171
168
  font-weight: bold;
172
169
  }
173
170
  .math-fallback {
package/src/utils/math.ts CHANGED
@@ -1,16 +1,4 @@
1
- import Plurimath from '@plurimath/plurimath';
2
-
3
- type MathFormat = 'asciimath' | 'latex' | 'mathml' | 'html' | 'mahtml' | 'omml';
4
-
5
- function renderMathSpan(math: string, format: MathFormat, bold: boolean): string {
6
- try {
7
- const p = new Plurimath(math, format);
8
- const mathml = p.toMathml();
9
- return `<span class="math-inline${bold ? ' math-bold' : ''}">${mathml}</span>`;
10
- } catch {
11
- return `<code class="math-fallback">${escapeHtml(math)}</code>`;
12
- }
13
- }
1
+ import katex from 'katex';
14
2
 
15
3
  export type XrefResolver = (uri: string, term: string) => string;
16
4
  export type BibResolver = (refId: string, title: string) => string;
@@ -22,12 +10,7 @@ export interface RenderOptions {
22
10
  figResolver?: FigResolver;
23
11
  }
24
12
 
25
- /**
26
- * Convert `* item` lines into <ul><li> blocks.
27
- * Also handles `1)` and `1.` numbered items into ordered lists.
28
- */
29
13
  function convertLists(text: string): string {
30
- // Unordered: * item (separated by \n or \n\n)
31
14
  let result = text.replace(/(?:^|\n)((?:[ \t]*\* [^\n]+)(?:\n[ \t]*\* [^\n]+)*)/g, (_, block) => {
32
15
  if (/^\*stem:\[/.test(block.trimStart())) return _;
33
16
  const items: string[] = [];
@@ -41,7 +24,6 @@ function convertLists(text: string): string {
41
24
  return `\n<ul class="concept-list">${lis}</ul>`;
42
25
  });
43
26
 
44
- // Ordered: 1) item or 1. item (numbered items)
45
27
  result = result.replace(/(?:^|\n)((?:[ \t]*\d+[).][ \t]+[^\n]+)(?:\n[ \t]*\d+[).][ \t]+[^\n]+)*)/g, (_, block) => {
46
28
  const items: string[] = [];
47
29
  const re = /[ \t]*\d+[).][ \t]+([^\n]+)/g;
@@ -57,10 +39,6 @@ function convertLists(text: string): string {
57
39
  return result;
58
40
  }
59
41
 
60
- /**
61
- * Replace `prefix:[content]` where content may contain nested brackets.
62
- * Handles `*prefix:[content]*` (bold) too.
63
- */
64
42
  function replaceBracketed(
65
43
  text: string,
66
44
  prefix: string,
@@ -70,11 +48,8 @@ function replaceBracketed(
70
48
  let i = 0;
71
49
  const boldPrefix = '*' + prefix;
72
50
  while (i < text.length) {
73
- // Check for bold variant: *prefix:[...]
74
51
  if (text.startsWith(boldPrefix + '[', i)) {
75
- const start = i;
76
- i += boldPrefix.length + 1; // skip *prefix:[
77
- const depth = 1;
52
+ i += boldPrefix.length + 1;
78
53
  let j = i;
79
54
  let d = 1;
80
55
  while (j < text.length && d > 0) {
@@ -83,13 +58,11 @@ function replaceBracketed(
83
58
  j++;
84
59
  }
85
60
  const content = text.slice(i, j - 1);
86
- // Check for closing *
87
61
  let end = j;
88
62
  if (end < text.length && text[end] === '*') end++;
89
63
  result += render(content, true);
90
64
  i = end;
91
65
  }
92
- // Check for normal variant: prefix:[...]
93
66
  else if (text.startsWith(prefix + '[', i)) {
94
67
  i += prefix.length + 1;
95
68
  let j = i;
@@ -110,10 +83,6 @@ function replaceBracketed(
110
83
  return result;
111
84
  }
112
85
 
113
- /**
114
- * Render stem:[...] math notation to KaTeX HTML.
115
- * Also handles cross-reference inline patterns (URN refs, bibliography, figures).
116
- */
117
86
  export function renderMath(text: string, xrefResolverOrOpts?: XrefResolver | RenderOptions): string {
118
87
  if (!text) return '';
119
88
  let result = text;
@@ -122,15 +91,14 @@ export function renderMath(text: string, xrefResolverOrOpts?: XrefResolver | Ren
122
91
  ? { xrefResolver: xrefResolverOrOpts }
123
92
  : (xrefResolverOrOpts ?? {});
124
93
 
125
- result = replaceBracketed(result, 'stem:', (math, bold) => renderMathSpan(math, 'asciimath', bold));
126
- result = replaceBracketed(result, 'latexmath:', (math, bold) => renderMathSpan(math, 'latex', bold));
94
+ result = replaceBracketed(result, 'stem:', renderKatexSpan);
95
+ result = replaceBracketed(result, 'latexmath:', renderKatexSpan);
127
96
 
128
97
  result = convertLists(result);
129
98
 
130
99
  result = result.replace(/\*([^*]+)\*/g, '<em>$1</em>');
131
100
  result = result.replace(/~([^~]+)~/g, '<sub>$1</sub>');
132
101
 
133
- // Handle AsciiDoc bibliography xrefs: <<ref_XX,title>>
134
102
  result = result.replace(/<<([^,>]+),([^>]+)>>/g, (_, refId, title) => {
135
103
  if (opts.bibResolver) {
136
104
  return opts.bibResolver(refId.trim(), title.trim());
@@ -138,7 +106,6 @@ export function renderMath(text: string, xrefResolverOrOpts?: XrefResolver | Ren
138
106
  return `<span class="bib-ref">${escapeHtml(title.trim())}</span>`;
139
107
  });
140
108
 
141
- // Handle AsciiDoc figure xrefs: <<fig_XX>>
142
109
  result = result.replace(/<<(fig_[^>]+)>>/g, (_, figId) => {
143
110
  if (opts.figResolver) {
144
111
  return opts.figResolver(figId.trim());
@@ -146,30 +113,40 @@ export function renderMath(text: string, xrefResolverOrOpts?: XrefResolver | Ren
146
113
  return `<span class="fig-ref">${escapeHtml(figId.trim())}</span>`;
147
114
  });
148
115
 
149
- // Handle URN inline refs: {{urn:...,term[,displayText]}} (double-braced)
150
116
  result = result.replace(/\{\{(urn:[^,}]+),([^,}]+)(?:,([^}]+))?\}\}/g, (_, uri, term, display) => {
151
- const text = (display || term).trim();
117
+ const t = (display || term).trim();
152
118
  if (opts.xrefResolver) {
153
- return opts.xrefResolver(uri, text);
119
+ return opts.xrefResolver(uri, t);
154
120
  }
155
- return text;
121
+ return t;
156
122
  });
157
123
 
158
- // Handle URN inline refs: {urn:...,term[,displayText]} (single-braced)
159
124
  result = result.replace(/\{(urn:[^,}]+),([^,}]+)(?:,([^}]+))?\}/g, (_, uri, term, display) => {
160
- const text = (display || term).trim();
125
+ const t = (display || term).trim();
161
126
  if (opts.xrefResolver) {
162
- return opts.xrefResolver(uri, text);
127
+ return opts.xrefResolver(uri, t);
163
128
  }
164
- return text;
129
+ return t;
165
130
  });
166
131
 
167
- // Handle any remaining {{...}} refs (fallback: show term before comma)
168
132
  result = result.replace(/\{\{([^,}]+)(?:,\s*[^}]+)?\}\}/g, '$1');
169
133
 
170
134
  return result;
171
135
  }
172
136
 
137
+ function renderKatexSpan(math: string, bold: boolean): string {
138
+ try {
139
+ const html = katex.renderToString(math, {
140
+ throwOnError: false,
141
+ displayMode: false,
142
+ output: 'html',
143
+ });
144
+ return `<span class="math-inline${bold ? ' math-bold' : ''}">${html}</span>`;
145
+ } catch {
146
+ return `<code class="math-fallback">${escapeHtml(math)}</code>`;
147
+ }
148
+ }
149
+
173
150
  function escapeHtml(text: string): string {
174
151
  return text
175
152
  .replace(/&/g, '&amp;')
@@ -177,9 +154,6 @@ function escapeHtml(text: string): string {
177
154
  .replace(/>/g, '&gt;');
178
155
  }
179
156
 
180
- /**
181
- * Clean content for plain text display (no math rendering).
182
- */
183
157
  export function cleanContent(text: string): string {
184
158
  if (!text) return '';
185
159
  let result = text
package/vite.config.ts CHANGED
@@ -20,9 +20,6 @@ export default defineConfig({
20
20
  '@': resolve(__dirname, 'src'),
21
21
  },
22
22
  },
23
- optimizeDeps: {
24
- include: ['@plurimath/plurimath'],
25
- },
26
23
  test: {
27
24
  environment: 'happy-dom',
28
25
  globals: true,