@glossarist/concept-browser 0.7.124 → 0.7.126
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/scripts/bridge-to-astro.js +1 -1
- package/scripts/build-edges.js +1 -1
- package/scripts/generate-data.js +35 -5
- package/scripts/generate-data.ts +41 -1
- package/scripts/lib/concept-uri.ts +4 -1
- package/scripts/validate-links.js +1 -1
- package/scripts/validate-links.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glossarist/concept-browser",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.126",
|
|
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": {
|
package/scripts/build-edges.js
CHANGED
package/scripts/generate-data.js
CHANGED
|
@@ -543,7 +543,7 @@ function normalizeBibliography(raw) {
|
|
|
543
543
|
|
|
544
544
|
// scripts/lib/concept-uri.ts
|
|
545
545
|
function buildConceptUri(uriBase, registerId, conceptId) {
|
|
546
|
-
return `${uriBase}/${registerId}/concept/${conceptId}`;
|
|
546
|
+
return `${uriBase}/dataset/${registerId}/concept/${conceptId}`;
|
|
547
547
|
}
|
|
548
548
|
|
|
549
549
|
// scripts/lib/harmonize-concept.ts
|
|
@@ -1887,18 +1887,47 @@ function processNewsPage(config2, page) {
|
|
|
1887
1887
|
writeJson(path3.join(PUBLIC, "news.json"), index);
|
|
1888
1888
|
console.log(`Generated news index: ${index.length} posts, ${postFiles.length} files copied to public/news/`);
|
|
1889
1889
|
}
|
|
1890
|
+
function convertAsciiDocTables(text) {
|
|
1891
|
+
return text.replace(/\n?\|===\n([\s\S]*?)\n\|===/g, (_, body) => {
|
|
1892
|
+
const rows = body.split("\n").filter((line) => line.trim() !== "");
|
|
1893
|
+
if (!rows.length) return "";
|
|
1894
|
+
const parsedRows = rows.map((row) => {
|
|
1895
|
+
const cellText = row.replace(/^\s*\|/, "").trim();
|
|
1896
|
+
return cellText.split(/\s*\|\s*/).map((c) => c.trim()).filter((c) => c !== "");
|
|
1897
|
+
}).filter((r) => r.length > 0);
|
|
1898
|
+
if (!parsedRows.length) return "";
|
|
1899
|
+
const maxCols = Math.max(...parsedRows.map((r) => r.length));
|
|
1900
|
+
const normalized = parsedRows.map((r) => {
|
|
1901
|
+
while (r.length < maxCols) r.push("");
|
|
1902
|
+
return r;
|
|
1903
|
+
});
|
|
1904
|
+
const thead = "<thead><tr>" + normalized[0].map((c) => `<th>${c}</th>`).join("") + "</tr></thead>";
|
|
1905
|
+
const tbody = "<tbody>" + normalized.slice(1).map(
|
|
1906
|
+
(r) => "<tr>" + r.map((c) => `<td>${c}</td>`).join("") + "</tr>"
|
|
1907
|
+
).join("") + "</tbody>";
|
|
1908
|
+
return `<table class="asciidoc-table">${thead}${tbody}</table>`;
|
|
1909
|
+
});
|
|
1910
|
+
}
|
|
1890
1911
|
function renderMarkdown(input) {
|
|
1912
|
+
let text = convertAsciiDocTables(input);
|
|
1913
|
+
const HTML_PASS_THROUGH = /<span\s+class="math-pending"[^>]*>[^<]*<\/span>/g;
|
|
1914
|
+
const htmlPlaceholders = [];
|
|
1915
|
+
text = text.replace(HTML_PASS_THROUGH, (match) => {
|
|
1916
|
+
const idx = htmlPlaceholders.length;
|
|
1917
|
+
htmlPlaceholders.push(match);
|
|
1918
|
+
return `\0HTML${idx}\0`;
|
|
1919
|
+
});
|
|
1891
1920
|
const INLINE_PATTERNS = [
|
|
1892
1921
|
[/\*\*(.+?)\*\*/g, (m) => `<strong>${m[1]}</strong>`],
|
|
1893
1922
|
[/(?<!\*)\*([^*]+?)\*(?!\*)/g, (m) => `<em>${m[1]}</em>`],
|
|
1894
1923
|
[/`([^`]+?)`/g, (m) => `<code>${m[1]}</code>`],
|
|
1895
1924
|
[/\[([^\]]+)\]\(([^)]+)\)/g, (m) => `<a href="${m[2]}" target="_blank">${m[1]}</a>`]
|
|
1896
1925
|
];
|
|
1897
|
-
function renderInline(
|
|
1926
|
+
function renderInline(text2) {
|
|
1898
1927
|
for (const [re, fn] of INLINE_PATTERNS) {
|
|
1899
|
-
|
|
1928
|
+
text2 = text2.replace(re, (...args) => fn(args));
|
|
1900
1929
|
}
|
|
1901
|
-
return
|
|
1930
|
+
return text2;
|
|
1902
1931
|
}
|
|
1903
1932
|
function escapeHtml(s) {
|
|
1904
1933
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
@@ -1982,7 +2011,8 @@ function renderMarkdown(input) {
|
|
|
1982
2011
|
}
|
|
1983
2012
|
if (pl.length) blocks.push(`<p>${renderInline(pl.join(" "))}</p>`);
|
|
1984
2013
|
}
|
|
1985
|
-
|
|
2014
|
+
const result = blocks.join("\n").replace(/ HTML(\d+) /g, (_, idx) => htmlPlaceholders[parseInt(idx)]);
|
|
2015
|
+
return result;
|
|
1986
2016
|
}
|
|
1987
2017
|
function processContentPage(config2, page) {
|
|
1988
2018
|
if (!page.source) {
|
package/scripts/generate-data.ts
CHANGED
|
@@ -1265,7 +1265,45 @@ function processNewsPage(config, page) {
|
|
|
1265
1265
|
|
|
1266
1266
|
// --- Markdown-lite renderer (isomorphic, same logic as src/utils/markdown-lite.ts) ---
|
|
1267
1267
|
|
|
1268
|
+
// Convert AsciiDoc table syntax to HTML table.
|
|
1269
|
+
// Matches: |=== ... |=== (with optional leading newline)
|
|
1270
|
+
// Row format: | cell1 | cell2 | cell3 |
|
|
1271
|
+
function convertAsciiDocTables(text: string): string {
|
|
1272
|
+
return text.replace(/\n?\|===\n([\s\S]*?)\n\|===/g, (_: string, body: string) => {
|
|
1273
|
+
const rows = body.split('\n').filter(line => line.trim() !== '');
|
|
1274
|
+
if (!rows.length) return '';
|
|
1275
|
+
const parsedRows = rows.map(row => {
|
|
1276
|
+
const cellText = row.replace(/^\s*\|/, '').trim();
|
|
1277
|
+
return cellText.split(/\s*\|\s*/).map(c => c.trim()).filter(c => c !== '');
|
|
1278
|
+
}).filter(r => r.length > 0);
|
|
1279
|
+
if (!parsedRows.length) return '';
|
|
1280
|
+
const maxCols = Math.max(...parsedRows.map(r => r.length));
|
|
1281
|
+
const normalized = parsedRows.map(r => {
|
|
1282
|
+
while (r.length < maxCols) r.push('');
|
|
1283
|
+
return r;
|
|
1284
|
+
});
|
|
1285
|
+
const thead = '<thead><tr>' + normalized[0].map(c => `<th>${c}</th>`).join('') + '</tr></thead>';
|
|
1286
|
+
const tbody = '<tbody>' + normalized.slice(1).map(r =>
|
|
1287
|
+
'<tr>' + r.map(c => `<td>${c}</td>`).join('') + '</tr>'
|
|
1288
|
+
).join('') + '</tbody>';
|
|
1289
|
+
return `<table class="asciidoc-table">${thead}${tbody}</table>`;
|
|
1290
|
+
});
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1268
1293
|
function renderMarkdown(input: string): string {
|
|
1294
|
+
// First convert AsciiDoc tables to HTML
|
|
1295
|
+
let text = convertAsciiDocTables(input);
|
|
1296
|
+
|
|
1297
|
+
// Allow specific HTML tags to pass through (math spans, etc.)
|
|
1298
|
+
// These are author-controlled content embedded in the dataset, not user input.
|
|
1299
|
+
const HTML_PASS_THROUGH = /<span\s+class="math-pending"[^>]*>[^<]*<\/span>/g;
|
|
1300
|
+
const htmlPlaceholders: string[] = [];
|
|
1301
|
+
text = text.replace(HTML_PASS_THROUGH, (match) => {
|
|
1302
|
+
const idx = htmlPlaceholders.length;
|
|
1303
|
+
htmlPlaceholders.push(match);
|
|
1304
|
+
return `HTML${idx}`;
|
|
1305
|
+
});
|
|
1306
|
+
|
|
1269
1307
|
const INLINE_PATTERNS: [RegExp, (m: string[]) => string][] = [
|
|
1270
1308
|
[/\*\*(.+?)\*\*/g, m => `<strong>${m[1]}</strong>`],
|
|
1271
1309
|
[/(?<!\*)\*([^*]+?)\*(?!\*)/g, m => `<em>${m[1]}</em>`],
|
|
@@ -1332,7 +1370,9 @@ function renderMarkdown(input: string): string {
|
|
|
1332
1370
|
while (i < lines.length && lines[i].trim() && !/^#{1,4}\s/.test(lines[i]) && !/^\s*[-*]\s+/.test(lines[i]) && !/^\s*\d+\.\s+/.test(lines[i]) && !/^>\s?/.test(lines[i]) && !lines[i].trimStart().startsWith('```')) { pl.push(lines[i]); i++; }
|
|
1333
1371
|
if (pl.length) blocks.push(`<p>${renderInline(pl.join(' '))}</p>`);
|
|
1334
1372
|
}
|
|
1335
|
-
|
|
1373
|
+
// Restore HTML pass-through placeholders
|
|
1374
|
+
const result = blocks.join('\n').replace(/ HTML(\d+) /g, (_, idx) => htmlPlaceholders[parseInt(idx)]);
|
|
1375
|
+
return result;
|
|
1336
1376
|
}
|
|
1337
1377
|
|
|
1338
1378
|
function processContentPage(config: Record<string, any>, page: Record<string, any>) {
|
|
@@ -7,8 +7,11 @@
|
|
|
7
7
|
* scripts/build-edges.ts
|
|
8
8
|
*
|
|
9
9
|
* DRY: all three now import from here.
|
|
10
|
+
*
|
|
11
|
+
* The /dataset/ segment matches the Vue Router route pattern
|
|
12
|
+
* /dataset/:register/concept/:conceptId used by the deployed SPA.
|
|
10
13
|
*/
|
|
11
14
|
|
|
12
15
|
export function buildConceptUri(uriBase: string, registerId: string, conceptId: string | number): string {
|
|
13
|
-
return `${uriBase}/${registerId}/concept/${conceptId}`;
|
|
16
|
+
return `${uriBase}/dataset/${registerId}/concept/${conceptId}`;
|
|
14
17
|
}
|
|
@@ -27,7 +27,7 @@ function checkFile(file, dataDir) {
|
|
|
27
27
|
const json = JSON.parse(raw);
|
|
28
28
|
const broken = [];
|
|
29
29
|
function check(target, field) {
|
|
30
|
-
if (!target) return;
|
|
30
|
+
if (!target || typeof target !== "string") return;
|
|
31
31
|
if (!target.startsWith("http")) return;
|
|
32
32
|
const { exists, expected } = localPathForUri(target, dataDir);
|
|
33
33
|
if (!exists) {
|
|
@@ -56,7 +56,7 @@ function checkFile(file: string, dataDir: string): BrokenLink[] {
|
|
|
56
56
|
const broken: BrokenLink[] = [];
|
|
57
57
|
|
|
58
58
|
function check(target: string | undefined, field: string) {
|
|
59
|
-
if (!target) return;
|
|
59
|
+
if (!target || typeof target !== 'string') return;
|
|
60
60
|
if (!target.startsWith('http')) return; // External links checked separately
|
|
61
61
|
const { exists, expected } = localPathForUri(target, dataDir);
|
|
62
62
|
if (!exists) {
|