@glossarist/concept-browser 0.7.115 → 0.7.116
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/cli/index.mjs +12 -15
- package/package.json +5 -1
- package/scripts/bridge-to-astro.js +132 -0
- package/scripts/build-edges.js +480 -0
- package/scripts/build-scripts.mjs +22 -0
- package/scripts/check-syntax.js +81 -0
- package/scripts/doctor.js +278 -0
- package/scripts/extract-source-refs.js +24 -0
- package/scripts/fetch-datasets.js +278 -0
- package/scripts/generate-404.js +14 -0
- package/scripts/generate-data.js +2220 -0
- package/scripts/generate-ontology-data.js +139 -0
- package/scripts/generate-ontology-schema.js +472 -0
- package/scripts/load-site-config.js +83 -0
- package/scripts/migrate-v1-to-v3.js +113 -0
- package/scripts/normalize-yaml.js +96 -0
- package/scripts/process-about-pages.js +241 -0
- package/scripts/smoke.js +211 -0
- package/scripts/sync-concept-model.js +63 -0
- package/scripts/validate-shacl.js +152 -0
- package/scripts/validate-yaml.js +132 -0
- package/src/__tests__/published-package-contract.test.ts +84 -0
- package/src/__tests__/scripts-syntax.test.ts +2 -2
- package/src/data/ontology-schema.json +1336 -183
package/cli/index.mjs
CHANGED
|
@@ -3,15 +3,12 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* Glossarist Concept Browser CLI — runtime entrypoint.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* Imports compiled .js scripts (not .ts) because Node.js v24+ blocks
|
|
7
|
+
* type stripping for files under node_modules. Scripts are compiled
|
|
8
|
+
* to .js by `npm run build:scripts` during prepublishOnly.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import {
|
|
12
|
-
register('tsx/esm', import.meta.url);
|
|
13
|
-
|
|
14
|
-
import { loadSiteConfig } from '../scripts/load-site-config.ts';
|
|
11
|
+
import { loadSiteConfig } from '../scripts/load-site-config.js';
|
|
15
12
|
import { existsSync } from 'fs';
|
|
16
13
|
import { resolve, dirname } from 'path';
|
|
17
14
|
import { fileURLToPath } from 'url';
|
|
@@ -20,10 +17,10 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
20
17
|
const pkgRoot = resolve(__dirname, '..');
|
|
21
18
|
|
|
22
19
|
const commands = {
|
|
23
|
-
fetch: async () => (await import('../scripts/fetch-datasets.
|
|
24
|
-
generate: async () => { await import('../scripts/generate-data.
|
|
25
|
-
edges: async () => (await import('../scripts/build-edges.
|
|
26
|
-
about: async () => (await import('../scripts/process-about-pages.
|
|
20
|
+
fetch: async () => (await import('../scripts/fetch-datasets.js')).main(),
|
|
21
|
+
generate: async () => { await import('../scripts/generate-data.js'); },
|
|
22
|
+
edges: async () => (await import('../scripts/build-edges.js')).main(),
|
|
23
|
+
about: async () => (await import('../scripts/process-about-pages.js')).main(),
|
|
27
24
|
};
|
|
28
25
|
|
|
29
26
|
function parseArgs(argv) {
|
|
@@ -294,7 +291,7 @@ Environment:
|
|
|
294
291
|
}
|
|
295
292
|
|
|
296
293
|
console.log(`\n=== BRIDGE DATA ===\n`);
|
|
297
|
-
const bridge = resolve(pkgRoot, 'scripts', 'bridge-to-astro.
|
|
294
|
+
const bridge = resolve(pkgRoot, 'scripts', 'bridge-to-astro.js');
|
|
298
295
|
if (existsSync(bridge)) {
|
|
299
296
|
await import(`file://${bridge}`);
|
|
300
297
|
}
|
|
@@ -319,7 +316,7 @@ Environment:
|
|
|
319
316
|
await viteBuild({ configFile: viteConfig, root: pkgRoot, mode: 'production' });
|
|
320
317
|
}
|
|
321
318
|
|
|
322
|
-
const postbuild = resolve(pkgRoot, 'scripts', 'generate-404.
|
|
319
|
+
const postbuild = resolve(pkgRoot, 'scripts', 'generate-404.js');
|
|
323
320
|
if (existsSync(postbuild)) {
|
|
324
321
|
await import(`file://${postbuild}`);
|
|
325
322
|
}
|
|
@@ -334,7 +331,7 @@ Environment:
|
|
|
334
331
|
}
|
|
335
332
|
|
|
336
333
|
if (cmd === 'normalize') {
|
|
337
|
-
const { normalizeYaml } = await import('../scripts/normalize-yaml.
|
|
334
|
+
const { normalizeYaml } = await import('../scripts/normalize-yaml.js');
|
|
338
335
|
const check = process.argv.includes('--check');
|
|
339
336
|
const paths = process.argv.slice(2).filter(a => !a.startsWith('-') && a !== 'normalize');
|
|
340
337
|
const { checked, nonNfc, fixed } = normalizeYaml({ check, paths });
|
|
@@ -357,7 +354,7 @@ Environment:
|
|
|
357
354
|
}
|
|
358
355
|
|
|
359
356
|
if (cmd === 'doctor') {
|
|
360
|
-
const { main: doctorMain } = await import('../scripts/doctor.
|
|
357
|
+
const { main: doctorMain } = await import('../scripts/doctor.js');
|
|
361
358
|
await doctorMain();
|
|
362
359
|
return;
|
|
363
360
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glossarist/concept-browser",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.116",
|
|
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": {
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
"sync:model": "tsx scripts/sync-concept-model.ts",
|
|
23
23
|
"build:full": "npm run generate-ontology && npm run fetch-datasets && npm run generate-data && tsx scripts/build-edges.ts && npm run build",
|
|
24
24
|
"build:site": "concept-browser --site build",
|
|
25
|
+
"build:scripts": "node scripts/build-scripts.mjs",
|
|
26
|
+
"prepublishOnly": "npm run build:scripts",
|
|
25
27
|
"smoke": "tsx scripts/smoke.ts",
|
|
26
28
|
"test": "vitest run",
|
|
27
29
|
"test:watch": "vitest",
|
|
@@ -57,6 +59,8 @@
|
|
|
57
59
|
"@stryker-mutator/vitest-runner": "^9.6.1",
|
|
58
60
|
"@types/d3": "^7.4.3",
|
|
59
61
|
"@types/n3": "^1.26.1",
|
|
62
|
+
"esbuild": "^0.28.1",
|
|
63
|
+
"glob": "^10.5.0",
|
|
60
64
|
"@vue/test-utils": "^2.4.8",
|
|
61
65
|
"fast-check": "^4.8.0",
|
|
62
66
|
"happy-dom": "^20.9.0",
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// scripts/lib/concept-uri.ts
|
|
2
|
+
function buildConceptUri(uriBase, registerId, conceptId) {
|
|
3
|
+
return `${uriBase}/${registerId}/concept/${conceptId}`;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
// scripts/bridge-to-astro.ts
|
|
7
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync, readdirSync } from "fs";
|
|
8
|
+
import { join } from "path";
|
|
9
|
+
var CWD = process.cwd();
|
|
10
|
+
var PUBLIC_DATA = join(CWD, "public", "data");
|
|
11
|
+
var PUBLIC_ROOT = join(CWD, "public");
|
|
12
|
+
var CONTENT_DIR = join(CWD, ".cb-content");
|
|
13
|
+
function readJson(p) {
|
|
14
|
+
if (!existsSync(p)) return null;
|
|
15
|
+
return JSON.parse(readFileSync(p, "utf-8"));
|
|
16
|
+
}
|
|
17
|
+
function writeJson(dir, name, data) {
|
|
18
|
+
mkdirSync(dir, { recursive: true });
|
|
19
|
+
writeFileSync(join(dir, name), JSON.stringify(data, null, 2));
|
|
20
|
+
}
|
|
21
|
+
var registryPath = join(PUBLIC_ROOT, "datasets.json");
|
|
22
|
+
var siteConfigPath = join(PUBLIC_ROOT, "site-config.json");
|
|
23
|
+
var registry = readJson(registryPath) || [];
|
|
24
|
+
var siteConfig = readJson(siteConfigPath) || {};
|
|
25
|
+
console.log(`Bridging ${registry.length} datasets to content collections...`);
|
|
26
|
+
for (const reg of registry) {
|
|
27
|
+
const id = reg.id;
|
|
28
|
+
const manifestPath = join(PUBLIC_DATA, id, "manifest.json");
|
|
29
|
+
const manifest = readJson(manifestPath);
|
|
30
|
+
if (!manifest) {
|
|
31
|
+
console.warn(` Skipping ${id}: no manifest.json`);
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const summary = reg.summary || {};
|
|
35
|
+
const entry = {
|
|
36
|
+
id: manifest.id || id,
|
|
37
|
+
title: summary.title || manifest.title || id,
|
|
38
|
+
description: summary.description || manifest.description || "",
|
|
39
|
+
uri: manifest.datasetUri || reg.datasetUri || "",
|
|
40
|
+
uriBase: manifest.uriBase || reg.uriBase || "",
|
|
41
|
+
year: manifest.year ?? summary.year ?? void 0,
|
|
42
|
+
status: manifest.status || summary.status || "valid",
|
|
43
|
+
ref: manifest.ref || reg.ref || void 0,
|
|
44
|
+
refAliases: manifest.refAliases || reg.refAliases || void 0,
|
|
45
|
+
owner: summary.owner || manifest.owner || "",
|
|
46
|
+
languages: manifest.languages || summary.languages || ["eng"],
|
|
47
|
+
conceptCount: manifest.conceptCount || summary.conceptCount || 0,
|
|
48
|
+
color: summary.color || manifest.color || void 0,
|
|
49
|
+
tags: summary.tags || manifest.tags || [],
|
|
50
|
+
sections: manifest.sections || [],
|
|
51
|
+
sourceRepo: manifest.sourceRepo || "",
|
|
52
|
+
lastUpdated: manifest.lastUpdated || ""
|
|
53
|
+
};
|
|
54
|
+
Object.keys(entry).forEach((k) => entry[k] === void 0 && delete entry[k]);
|
|
55
|
+
writeJson(join(CONTENT_DIR, "datasets"), `${id}.json`, entry);
|
|
56
|
+
console.log(` Dataset: ${id} (${entry.conceptCount} concepts)`);
|
|
57
|
+
const indexPath = join(PUBLIC_DATA, id, "index.json");
|
|
58
|
+
const index = readJson(indexPath);
|
|
59
|
+
if (index && index.concepts) {
|
|
60
|
+
for (const concept of index.concepts) {
|
|
61
|
+
if (!concept) continue;
|
|
62
|
+
const conceptEntry = {
|
|
63
|
+
registerId: id,
|
|
64
|
+
conceptId: concept.id,
|
|
65
|
+
uri: buildConceptUri(entry.uriBase || "", id, concept.id),
|
|
66
|
+
status: concept.status || "valid",
|
|
67
|
+
designations: concept.designations || {},
|
|
68
|
+
eng: concept.eng || concept.designations?.eng || "",
|
|
69
|
+
groups: concept.groups || [],
|
|
70
|
+
tags: []
|
|
71
|
+
};
|
|
72
|
+
const fullConceptPath = join(PUBLIC_DATA, id, "concepts", `${concept.id}.json`);
|
|
73
|
+
const fullConcept = readJson(fullConceptPath);
|
|
74
|
+
if (fullConcept) {
|
|
75
|
+
const lc = fullConcept["gl:localizedConcept"] || fullConcept.localizedConcept || {};
|
|
76
|
+
const localizations = {};
|
|
77
|
+
for (const [lang, loc] of Object.entries(lc)) {
|
|
78
|
+
localizations[lang] = {
|
|
79
|
+
languageCode: loc["gl:languageCode"] || lang,
|
|
80
|
+
terms: (loc["gl:designation"] || []).map((d) => ({ designation: d["gl:term"] || d.term || "", normativeStatus: d["gl:normativeStatus"] || d.normativeStatus })).filter((d) => d.designation),
|
|
81
|
+
definitions: (loc["gl:definition"] || []).map((d) => ({ content: d["gl:content"] || d.content || "" })).filter((d) => d.content),
|
|
82
|
+
notes: (loc["gl:notes"] || []).map((n) => ({ content: n["gl:content"] || n.content || "" })).filter((n) => n.content),
|
|
83
|
+
examples: (loc["gl:examples"] || []).map((e) => ({ content: e["gl:content"] || e.content || "" })).filter((e) => e.content)
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
conceptEntry.localizations = localizations;
|
|
87
|
+
conceptEntry.languages = Object.keys(localizations);
|
|
88
|
+
}
|
|
89
|
+
writeJson(
|
|
90
|
+
join(CONTENT_DIR, "concepts", id),
|
|
91
|
+
`${concept.id}.json`,
|
|
92
|
+
conceptEntry
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
console.log(` ${index.concepts.filter(Boolean).length} concepts bridged`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
var groups = siteConfig.datasetGroups || [];
|
|
99
|
+
for (const g of groups) {
|
|
100
|
+
const entry = {
|
|
101
|
+
id: g.id,
|
|
102
|
+
label: g.label || g.id,
|
|
103
|
+
kind: g.kind || (g.series ? "lineage" : "default"),
|
|
104
|
+
description: g.description || "",
|
|
105
|
+
current: g.current || void 0,
|
|
106
|
+
datasets: g.datasets || [],
|
|
107
|
+
color: g.color || void 0
|
|
108
|
+
};
|
|
109
|
+
Object.keys(entry).forEach((k) => entry[k] === void 0 && delete entry[k]);
|
|
110
|
+
writeJson(join(CONTENT_DIR, "groups"), `${g.id}.json`, entry);
|
|
111
|
+
console.log(` Group: ${g.id} (${entry.datasets.length} datasets)`);
|
|
112
|
+
}
|
|
113
|
+
var pagesDir = join(CWD, "public", "pages");
|
|
114
|
+
if (existsSync(pagesDir)) {
|
|
115
|
+
mkdirSync(join(CONTENT_DIR, "pages"), { recursive: true });
|
|
116
|
+
for (const file of readdirSync(pagesDir)) {
|
|
117
|
+
if (!file.endsWith(".json")) continue;
|
|
118
|
+
const page = readJson(join(pagesDir, file));
|
|
119
|
+
if (!page) continue;
|
|
120
|
+
const slug = file.replace(".json", "");
|
|
121
|
+
const md = `---
|
|
122
|
+
title: "${page.title || slug}"
|
|
123
|
+
type: "page"
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
${page.html || ""}
|
|
127
|
+
`;
|
|
128
|
+
writeFileSync(join(CONTENT_DIR, "pages", `${slug}.md`), md);
|
|
129
|
+
}
|
|
130
|
+
console.log(" Pages bridged from public/pages/");
|
|
131
|
+
}
|
|
132
|
+
console.log("Data bridge complete.");
|