@glossarist/concept-browser 0.7.114 → 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/README.md +45 -2
- package/cli/index.mjs +10 -13
- package/cli/index.ts +9 -11
- package/data/concept-model/shapes/glossarist.concept.yaml.schema.json +255 -0
- package/package.json +18 -12
- package/scripts/__tests__/{bibliography.test.mjs → bibliography.test.ts} +1 -1
- package/scripts/__tests__/{cli-script-contract.test.mjs → cli-script-contract.test.ts} +3 -3
- package/scripts/__tests__/{concept-groups.test.mjs → concept-groups.test.ts} +1 -1
- package/scripts/__tests__/{doctor.test.mjs → doctor.test.ts} +1 -1
- package/scripts/__tests__/{fetch-datasets.test.mjs → fetch-datasets.test.ts} +1 -1
- package/scripts/__tests__/{first-non-empty.test.mjs → first-non-empty.test.ts} +1 -1
- package/scripts/__tests__/{process-about-pages.test.mjs → process-about-pages.test.ts} +1 -1
- package/scripts/bridge-to-astro.js +132 -0
- package/scripts/{bridge-to-astro.mjs → bridge-to-astro.ts} +2 -4
- package/scripts/build-edges.js +242 -336
- package/scripts/build-edges.ts +572 -0
- package/scripts/build-scripts.mjs +22 -0
- package/scripts/check-syntax.js +81 -0
- package/scripts/{check-syntax.mjs → check-syntax.ts} +20 -13
- package/scripts/doctor.js +278 -0
- package/scripts/extract-source-refs.js +16 -24
- package/scripts/extract-source-refs.ts +32 -0
- package/scripts/fetch-datasets.js +278 -0
- package/scripts/{fetch-datasets.mjs → fetch-datasets.ts} +2 -2
- package/scripts/generate-404.js +10 -11
- package/scripts/generate-404.ts +15 -0
- package/scripts/generate-data.js +2220 -0
- package/scripts/{generate-data.mjs → generate-data.ts} +73 -460
- package/scripts/generate-ontology-data.js +139 -0
- package/scripts/generate-ontology-schema.js +472 -0
- package/scripts/{generate-ontology-schema.mjs → generate-ontology-schema.ts} +2 -2
- package/scripts/lib/{build-cache.mjs → build-cache.ts} +3 -2
- package/scripts/lib/concept-formats.ts +206 -0
- package/scripts/lib/concept-uri.ts +14 -0
- package/scripts/lib/{dataset-turtle.mjs → dataset-turtle.ts} +4 -3
- package/scripts/lib/harmonize-concept.ts +86 -0
- package/scripts/lib/jsonld-emitter.ts +169 -0
- package/scripts/lib/{local-path-safety.mjs → local-path-safety.ts} +6 -2
- package/scripts/lib/yaml-types.ts +262 -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/{process-about-pages.mjs → process-about-pages.ts} +1 -1
- package/scripts/smoke.js +211 -0
- package/scripts/{smoke.mjs → smoke.ts} +4 -3
- package/scripts/sync-concept-model.js +63 -0
- package/scripts/validate-shacl.js +152 -0
- package/scripts/{validate-shacl.mjs → validate-shacl.ts} +5 -5
- package/scripts/validate-yaml.js +132 -0
- package/scripts/validate-yaml.ts +144 -0
- package/src/__tests__/extract-source-refs.test.ts +2 -3
- package/src/__tests__/perf/serialization-perf.test.ts +5 -5
- package/src/__tests__/published-package-contract.test.ts +84 -0
- package/src/__tests__/scripts/agents-turtle.test.ts +1 -1
- package/src/__tests__/scripts/bibliography-turtle.test.ts +1 -1
- package/src/__tests__/scripts/build-activity-turtle.test.ts +1 -1
- package/src/__tests__/scripts/build-cache.test.ts +1 -1
- package/src/__tests__/scripts/build-integration.test.ts +19 -19
- package/src/__tests__/scripts/dataset-turtle.test.ts +1 -1
- package/src/__tests__/scripts/migrate-v1-to-v3.test.ts +1 -1
- package/src/__tests__/scripts/normalize-yaml.test.ts +1 -1
- package/src/__tests__/scripts/turtle-escape.test.ts +1 -1
- package/src/__tests__/scripts/validate-yaml.test.ts +76 -0
- package/src/__tests__/scripts/version-turtle.test.ts +1 -1
- package/src/__tests__/scripts/vocab-turtle.test.ts +1 -1
- package/src/__tests__/scripts-syntax.test.ts +4 -4
- package/src/__tests__/use-rdf-document.test.ts +2 -3
- package/src/__tests__/utils/content-renderer-xss.test.ts +57 -0
- package/src/__tests__/validate-shacl.test.ts +3 -3
- package/src/adapters/wire/index.ts +69 -0
- package/src/data/ontology-schema.json +1336 -183
- package/src/utils/content-renderer.ts +7 -3
- package/src/utils/url-safety.ts +1 -5
- package/tsconfig.json +2 -2
- package/vite.config.ts +1 -1
- package/src/__tests__/composables/use-concept-edges-v2.test.ts +0 -167
- package/src/__tests__/composables/use-concept-edges-v2.test.ts.bak +0 -166
- package/src/types/agents-version-turtle.d.ts +0 -27
- package/src/types/bibliography-turtle.d.ts +0 -12
- package/src/types/build-activity-turtle.d.ts +0 -16
- package/src/types/build-cache.d.ts +0 -20
- package/src/types/dataset-turtle.d.ts +0 -32
- package/src/types/normalize-yaml.d.ts +0 -16
- package/src/types/turtle-escape.d.ts +0 -6
- package/src/types/vocab-turtle.d.ts +0 -13
- /package/scripts/{doctor.mjs → doctor.ts} +0 -0
- /package/scripts/{generate-ontology-data.mjs → generate-ontology-data.ts} +0 -0
- /package/scripts/lib/{agents-turtle.mjs → agents-turtle.ts} +0 -0
- /package/scripts/lib/{bibliography-turtle.mjs → bibliography-turtle.ts} +0 -0
- /package/scripts/lib/{bibliography.mjs → bibliography.ts} +0 -0
- /package/scripts/lib/build/{image-assets.mjs → image-assets.ts} +0 -0
- /package/scripts/lib/build/{non-verbal-consumer.mjs → non-verbal-consumer.ts} +0 -0
- /package/scripts/lib/{build-activity-turtle.mjs → build-activity-turtle.ts} +0 -0
- /package/scripts/lib/{concept-groups.mjs → concept-groups.ts} +0 -0
- /package/scripts/lib/{first-non-empty.mjs → first-non-empty.ts} +0 -0
- /package/scripts/lib/{turtle-escape.mjs → turtle-escape.ts} +0 -0
- /package/scripts/lib/{version-turtle.mjs → version-turtle.ts} +0 -0
- /package/scripts/lib/{vocab-turtle.mjs → vocab-turtle.ts} +0 -0
- /package/scripts/{load-site-config.mjs → load-site-config.ts} +0 -0
- /package/scripts/{migrate-v1-to-v3.mjs → migrate-v1-to-v3.ts} +0 -0
- /package/scripts/{normalize-yaml.mjs → normalize-yaml.ts} +0 -0
- /package/scripts/{sync-concept-model.mjs → sync-concept-model.ts} +0 -0
|
@@ -7,7 +7,8 @@ import process from "node:process";
|
|
|
7
7
|
const ROOT = path.resolve(path.dirname(new URL(import.meta.url).pathname), "..");
|
|
8
8
|
|
|
9
9
|
const TARGET_DIRS = ["scripts", "cli"];
|
|
10
|
-
const
|
|
10
|
+
const JS_EXTENSIONS = new Set([".mjs", ".js", ".cjs"]);
|
|
11
|
+
const ALL_EXTENSIONS = new Set([".ts", ...JS_EXTENSIONS]);
|
|
11
12
|
const SKIP_DIRS = new Set(["__tests__", "node_modules"]);
|
|
12
13
|
|
|
13
14
|
function walk(dir) {
|
|
@@ -18,7 +19,7 @@ function walk(dir) {
|
|
|
18
19
|
const st = statSync(full);
|
|
19
20
|
if (st.isDirectory()) {
|
|
20
21
|
out.push(...walk(full));
|
|
21
|
-
} else if (
|
|
22
|
+
} else if (ALL_EXTENSIONS.has(path.extname(entry))) {
|
|
22
23
|
out.push(full);
|
|
23
24
|
}
|
|
24
25
|
}
|
|
@@ -39,15 +40,24 @@ export function checkAllScripts({ root = ROOT } = {}) {
|
|
|
39
40
|
files.sort();
|
|
40
41
|
|
|
41
42
|
const failures = [];
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
|
|
44
|
+
// JS files: syntax-check with node --check
|
|
45
|
+
for (const file of files.filter(f => JS_EXTENSIONS.has(path.extname(f)))) {
|
|
46
|
+
const result = spawnSync(process.execPath, ["--check", file], { encoding: "utf8" });
|
|
47
|
+
if (result.status !== 0) {
|
|
48
|
+
failures.push({ file: path.relative(root, file), stderr: result.stderr || "" });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// TS files: type-check with tsc (authoritative for TypeScript)
|
|
53
|
+
if (files.some(f => path.extname(f) === ".ts")) {
|
|
54
|
+
const tsconfig = path.join(root, "tsconfig.scripts.json");
|
|
55
|
+
const result = spawnSync("npx", ["tsc", "-p", tsconfig, "--noEmit"], {
|
|
44
56
|
encoding: "utf8",
|
|
57
|
+
cwd: root,
|
|
45
58
|
});
|
|
46
59
|
if (result.status !== 0) {
|
|
47
|
-
failures.push({
|
|
48
|
-
file: path.relative(root, file),
|
|
49
|
-
stderr: result.stderr || "",
|
|
50
|
-
});
|
|
60
|
+
failures.push({ file: "tsconfig.scripts.json (tsc)", stderr: result.stdout || result.stderr || "" });
|
|
51
61
|
}
|
|
52
62
|
}
|
|
53
63
|
|
|
@@ -60,9 +70,7 @@ function main() {
|
|
|
60
70
|
process.stdout.write(`syntax OK: ${files.length} file(s) checked\n`);
|
|
61
71
|
return;
|
|
62
72
|
}
|
|
63
|
-
process.stderr.write(
|
|
64
|
-
`syntax check failed: ${failures.length} of ${files.length} file(s)\n\n`,
|
|
65
|
-
);
|
|
73
|
+
process.stderr.write(`syntax check failed: ${failures.length} of ${files.length} file(s)\n\n`);
|
|
66
74
|
for (const { file, stderr } of failures) {
|
|
67
75
|
process.stderr.write(`--- ${file} ---\n${stderr}\n`);
|
|
68
76
|
}
|
|
@@ -70,8 +78,7 @@ function main() {
|
|
|
70
78
|
}
|
|
71
79
|
|
|
72
80
|
const isDirectEntry = process.argv[1] &&
|
|
73
|
-
path.resolve(process.argv[1]) ===
|
|
74
|
-
path.resolve(new URL(import.meta.url).pathname);
|
|
81
|
+
path.resolve(process.argv[1]) === path.resolve(new URL(import.meta.url).pathname);
|
|
75
82
|
|
|
76
83
|
if (isDirectEntry) {
|
|
77
84
|
main();
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// scripts/doctor.ts
|
|
4
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
5
|
+
import { resolve, dirname, join } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import yaml from "js-yaml";
|
|
8
|
+
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
var PKG_ROOT = resolve(__dirname, "..");
|
|
10
|
+
var NODE_MIN_MAJOR = 18;
|
|
11
|
+
function safe(id, check) {
|
|
12
|
+
const wrapped = async (ctx) => {
|
|
13
|
+
try {
|
|
14
|
+
return await check(ctx);
|
|
15
|
+
} catch (err) {
|
|
16
|
+
return {
|
|
17
|
+
id: "unexpected",
|
|
18
|
+
label: "Unexpected error",
|
|
19
|
+
status: "fail",
|
|
20
|
+
detail: err?.message ?? String(err)
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
Object.defineProperty(wrapped, "name", { value: id });
|
|
25
|
+
return wrapped;
|
|
26
|
+
}
|
|
27
|
+
function nodeVersionCheck() {
|
|
28
|
+
const major = Number.parseInt(process.versions.node.split(".")[0], 10);
|
|
29
|
+
return {
|
|
30
|
+
id: "node-version",
|
|
31
|
+
label: `Node.js v${process.versions.node}`,
|
|
32
|
+
status: major >= NODE_MIN_MAJOR ? "pass" : "fail",
|
|
33
|
+
detail: major < NODE_MIN_MAJOR ? `requires >= v${NODE_MIN_MAJOR}` : void 0,
|
|
34
|
+
hint: major < NODE_MIN_MAJOR ? "upgrade via nvm or your package manager" : void 0
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function packageDepsCheck(ctx) {
|
|
38
|
+
const nm = resolve(ctx.pkgRoot, "node_modules");
|
|
39
|
+
if (!existsSync(nm)) {
|
|
40
|
+
return {
|
|
41
|
+
id: "package-deps",
|
|
42
|
+
label: "Dependencies installed",
|
|
43
|
+
status: "fail",
|
|
44
|
+
detail: "node_modules missing",
|
|
45
|
+
hint: "run `npm install`"
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const required = ["vue", "vue-router", "pinia", "vite", "n3", "glossarist", "@rdfjs/dataset"];
|
|
49
|
+
const missing = required.filter((p) => !existsSync(join(nm, p)));
|
|
50
|
+
if (missing.length) {
|
|
51
|
+
return {
|
|
52
|
+
id: "package-deps",
|
|
53
|
+
label: "Dependencies installed",
|
|
54
|
+
status: "fail",
|
|
55
|
+
detail: `missing: ${missing.join(", ")}`,
|
|
56
|
+
hint: "run `npm install`"
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return { id: "package-deps", label: "Dependencies installed", status: "pass" };
|
|
60
|
+
}
|
|
61
|
+
function datasetsYmlCheck(ctx) {
|
|
62
|
+
const path = resolve(ctx.cwd, "datasets.yml");
|
|
63
|
+
if (!existsSync(path)) {
|
|
64
|
+
return {
|
|
65
|
+
id: "datasets-yml",
|
|
66
|
+
label: "datasets.yml present",
|
|
67
|
+
status: "warn",
|
|
68
|
+
detail: "file not found at project root",
|
|
69
|
+
hint: "datasets.yml registers every dataset the browser serves"
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (ctx.datasetsYmlError) {
|
|
73
|
+
return {
|
|
74
|
+
id: "datasets-yml",
|
|
75
|
+
label: "datasets.yml parses",
|
|
76
|
+
status: "fail",
|
|
77
|
+
detail: ctx.datasetsYmlError,
|
|
78
|
+
hint: "fix the YAML syntax error"
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const datasets = ctx.datasetsYml?.datasets;
|
|
82
|
+
if (!Array.isArray(datasets) || datasets.length === 0) {
|
|
83
|
+
return {
|
|
84
|
+
id: "datasets-yml",
|
|
85
|
+
label: "datasets.yml lists datasets",
|
|
86
|
+
status: "warn",
|
|
87
|
+
detail: "`datasets` key is empty or missing",
|
|
88
|
+
hint: "add at least one dataset entry; see docs/adding-a-dataset.md"
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
id: "datasets-yml",
|
|
93
|
+
label: `datasets.yml lists ${datasets.length} dataset(s)`,
|
|
94
|
+
status: "pass"
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function datasetsFetchedCheck(ctx) {
|
|
98
|
+
const datasets = ctx.datasetsYml?.datasets ?? [];
|
|
99
|
+
if (!datasets.length) {
|
|
100
|
+
return { id: "datasets-fetched", label: "Source datasets fetched", status: "warn", detail: "no datasets registered" };
|
|
101
|
+
}
|
|
102
|
+
const dotDatasets = resolve(ctx.cwd, ".datasets");
|
|
103
|
+
const missing = datasets.filter((d) => !existsSync(join(dotDatasets, d.id, "concepts"))).map((d) => d.id);
|
|
104
|
+
if (missing.length) {
|
|
105
|
+
return {
|
|
106
|
+
id: "datasets-fetched",
|
|
107
|
+
label: "Source datasets fetched",
|
|
108
|
+
status: "fail",
|
|
109
|
+
detail: `.datasets/ missing: ${missing.join(", ")}`,
|
|
110
|
+
hint: "run `npm run fetch-datasets`"
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return { id: "datasets-fetched", label: "Source datasets fetched", status: "pass" };
|
|
114
|
+
}
|
|
115
|
+
function datasetsGeneratedCheck(ctx) {
|
|
116
|
+
const datasets = ctx.datasetsYml?.datasets ?? [];
|
|
117
|
+
if (!datasets.length) {
|
|
118
|
+
return { id: "datasets-generated", label: "Generated data present", status: "warn", detail: "no datasets registered" };
|
|
119
|
+
}
|
|
120
|
+
const publicData = resolve(ctx.cwd, "public", "data");
|
|
121
|
+
const missing = datasets.filter((d) => !existsSync(join(publicData, d.id, "manifest.json"))).map((d) => d.id);
|
|
122
|
+
if (missing.length) {
|
|
123
|
+
return {
|
|
124
|
+
id: "datasets-generated",
|
|
125
|
+
label: "Generated data present",
|
|
126
|
+
status: "fail",
|
|
127
|
+
detail: `public/data/ missing manifest for: ${missing.join(", ")}`,
|
|
128
|
+
hint: "run `npm run generate-data`"
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
return { id: "datasets-generated", label: "Generated data present", status: "pass" };
|
|
132
|
+
}
|
|
133
|
+
function publicDatasetsJsonCheck(ctx) {
|
|
134
|
+
const path = resolve(ctx.cwd, "public", "datasets.json");
|
|
135
|
+
if (!existsSync(path)) {
|
|
136
|
+
return {
|
|
137
|
+
id: "public-datasets-json",
|
|
138
|
+
label: "public/datasets.json present",
|
|
139
|
+
status: "fail",
|
|
140
|
+
hint: "run `npm run generate-data`"
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
const doc = JSON.parse(readFileSync(path, "utf8"));
|
|
145
|
+
if (!Array.isArray(doc) || doc.length === 0) {
|
|
146
|
+
return {
|
|
147
|
+
id: "public-datasets-json",
|
|
148
|
+
label: "public/datasets.json non-empty",
|
|
149
|
+
status: "warn",
|
|
150
|
+
detail: "datasets list is empty"
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
return { id: "public-datasets-json", label: "public/datasets.json parses", status: "pass" };
|
|
154
|
+
} catch (err) {
|
|
155
|
+
return {
|
|
156
|
+
id: "public-datasets-json",
|
|
157
|
+
label: "public/datasets.json parses",
|
|
158
|
+
status: "fail",
|
|
159
|
+
detail: err.message
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
function shaclShapesCheck(ctx) {
|
|
164
|
+
const shapesPath = resolve(ctx.pkgRoot, "data", "concept-model", "shapes", "glossarist.shacl.ttl");
|
|
165
|
+
if (!existsSync(shapesPath)) {
|
|
166
|
+
return {
|
|
167
|
+
id: "shacl-shapes",
|
|
168
|
+
label: "SHACL shapes present",
|
|
169
|
+
status: "fail",
|
|
170
|
+
hint: "run `npm run sync:model` to vendor shapes from concept-model"
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
const ttl = readFileSync(shapesPath, "utf8");
|
|
174
|
+
const looksLikeShapes = /sh:\s*(NodeShape|PropertyShape|targetClass)/.test(ttl) || /a\s+sh:NodeShape/.test(ttl);
|
|
175
|
+
if (!looksLikeShapes) {
|
|
176
|
+
return {
|
|
177
|
+
id: "shacl-shapes",
|
|
178
|
+
label: "SHACL shapes well-formed",
|
|
179
|
+
status: "fail",
|
|
180
|
+
detail: "file exists but does not declare any sh:NodeShape",
|
|
181
|
+
hint: "re-sync from glossarist/concept-model"
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
return { id: "shacl-shapes", label: "SHACL shapes present", status: "pass" };
|
|
185
|
+
}
|
|
186
|
+
function jsonldContextCheck(ctx) {
|
|
187
|
+
const ctxPath = resolve(ctx.pkgRoot, "data", "concept-model", "glossarist.context.jsonld");
|
|
188
|
+
if (!existsSync(ctxPath)) {
|
|
189
|
+
return {
|
|
190
|
+
id: "jsonld-context",
|
|
191
|
+
label: "JSON-LD context present",
|
|
192
|
+
status: "fail",
|
|
193
|
+
hint: "run `npm run sync:model` to vendor the context"
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
try {
|
|
197
|
+
const doc = JSON.parse(readFileSync(ctxPath, "utf8"));
|
|
198
|
+
if (!doc["@context"] || typeof doc["@context"] !== "object") {
|
|
199
|
+
return {
|
|
200
|
+
id: "jsonld-context",
|
|
201
|
+
label: "JSON-LD context well-formed",
|
|
202
|
+
status: "fail",
|
|
203
|
+
detail: "missing or invalid @context key"
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
return { id: "jsonld-context", label: "JSON-LD context present", status: "pass" };
|
|
207
|
+
} catch (err) {
|
|
208
|
+
return {
|
|
209
|
+
id: "jsonld-context",
|
|
210
|
+
label: "JSON-LD context parses",
|
|
211
|
+
status: "fail",
|
|
212
|
+
detail: err.message
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
var CHECKS = [
|
|
217
|
+
safe("node-version", nodeVersionCheck),
|
|
218
|
+
safe("package-deps", packageDepsCheck),
|
|
219
|
+
safe("datasets-yml", datasetsYmlCheck),
|
|
220
|
+
safe("datasets-fetched", datasetsFetchedCheck),
|
|
221
|
+
safe("datasets-generated", datasetsGeneratedCheck),
|
|
222
|
+
safe("public-datasets-json", publicDatasetsJsonCheck),
|
|
223
|
+
safe("shacl-shapes", shaclShapesCheck),
|
|
224
|
+
safe("jsonld-context", jsonldContextCheck)
|
|
225
|
+
];
|
|
226
|
+
async function runDoctor(cwd = process.cwd()) {
|
|
227
|
+
const datasetsYmlPath = resolve(cwd, "datasets.yml");
|
|
228
|
+
let datasetsYml;
|
|
229
|
+
let datasetsYmlError;
|
|
230
|
+
if (existsSync(datasetsYmlPath)) {
|
|
231
|
+
try {
|
|
232
|
+
datasetsYml = yaml.load(readFileSync(datasetsYmlPath, "utf8"));
|
|
233
|
+
} catch (err) {
|
|
234
|
+
datasetsYmlError = err.message;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
const ctx = { cwd, pkgRoot: PKG_ROOT, datasetsYml, datasetsYmlError };
|
|
238
|
+
const results = [];
|
|
239
|
+
for (const check of CHECKS) {
|
|
240
|
+
results.push(await check(ctx));
|
|
241
|
+
}
|
|
242
|
+
const failed = results.filter((r) => r.status === "fail").length;
|
|
243
|
+
const exitCode = failed > 0 ? 1 : 0;
|
|
244
|
+
return { results, exitCode };
|
|
245
|
+
}
|
|
246
|
+
var STATUS_GLYPH = { pass: "\u2713", fail: "\u2717", warn: "!" };
|
|
247
|
+
function formatResults(results) {
|
|
248
|
+
const lines = [];
|
|
249
|
+
for (const r of results) {
|
|
250
|
+
lines.push(`${STATUS_GLYPH[r.status]} ${r.label}`);
|
|
251
|
+
if (r.detail) lines.push(` ${r.detail}`);
|
|
252
|
+
if (r.hint) lines.push(` \u2192 ${r.hint}`);
|
|
253
|
+
}
|
|
254
|
+
const pass = results.filter((r) => r.status === "pass").length;
|
|
255
|
+
const fail = results.filter((r) => r.status === "fail").length;
|
|
256
|
+
const warn = results.filter((r) => r.status === "warn").length;
|
|
257
|
+
lines.push("");
|
|
258
|
+
lines.push(`${pass} passed, ${fail} failed, ${warn} warnings (${results.length} total)`);
|
|
259
|
+
return lines.join("\n");
|
|
260
|
+
}
|
|
261
|
+
async function main() {
|
|
262
|
+
const { results, exitCode } = await runDoctor();
|
|
263
|
+
console.log(formatResults(results));
|
|
264
|
+
process.exit(exitCode);
|
|
265
|
+
}
|
|
266
|
+
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
267
|
+
main().catch((err) => {
|
|
268
|
+
console.error(err);
|
|
269
|
+
process.exit(1);
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
export {
|
|
273
|
+
CHECKS,
|
|
274
|
+
NODE_MIN_MAJOR,
|
|
275
|
+
formatResults,
|
|
276
|
+
main,
|
|
277
|
+
runDoctor
|
|
278
|
+
};
|
|
@@ -1,32 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export function extractSourceRefs(concept, registerId) {
|
|
9
|
-
const refs = new Set();
|
|
10
|
-
|
|
11
|
-
// Managed concept-level sources
|
|
12
|
-
for (const src of concept['gl:source'] || []) {
|
|
13
|
-
const origin = src['gl:origin'];
|
|
1
|
+
// scripts/extract-source-refs.ts
|
|
2
|
+
function extractSourceRefs(concept, registerId) {
|
|
3
|
+
const refs = /* @__PURE__ */ new Set();
|
|
4
|
+
for (const src of concept["gl:source"] || []) {
|
|
5
|
+
const origin = src["gl:origin"];
|
|
14
6
|
if (origin) {
|
|
15
|
-
const ref = origin[
|
|
16
|
-
if (ref?.[
|
|
7
|
+
const ref = origin["gl:ref"];
|
|
8
|
+
if (ref?.["gl:source"]) refs.add(ref["gl:source"]);
|
|
17
9
|
}
|
|
18
10
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
for (const src of lc['gl:source'] || []) {
|
|
23
|
-
const origin = src['gl:origin'];
|
|
11
|
+
for (const lc of Object.values(concept["gl:localizedConcept"] || {})) {
|
|
12
|
+
for (const src of lc["gl:source"] || []) {
|
|
13
|
+
const origin = src["gl:origin"];
|
|
24
14
|
if (origin) {
|
|
25
|
-
const ref = origin[
|
|
26
|
-
if (ref?.[
|
|
15
|
+
const ref = origin["gl:ref"];
|
|
16
|
+
if (ref?.["gl:source"]) refs.add(ref["gl:source"]);
|
|
27
17
|
}
|
|
28
18
|
}
|
|
29
19
|
}
|
|
30
|
-
|
|
31
|
-
return [...refs].map(source => ({ source, registerId }));
|
|
20
|
+
return [...refs].map((source) => ({ source, registerId }));
|
|
32
21
|
}
|
|
22
|
+
export {
|
|
23
|
+
extractSourceRefs
|
|
24
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Source reference extraction for citation linking.
|
|
3
|
+
*
|
|
4
|
+
* Scans concept JSON-LD for source strings in gl:source fields.
|
|
5
|
+
* Used by build-edges.js to generate source-refs.json.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export function extractSourceRefs(concept, registerId) {
|
|
9
|
+
const refs = new Set();
|
|
10
|
+
|
|
11
|
+
// Managed concept-level sources
|
|
12
|
+
for (const src of concept['gl:source'] || []) {
|
|
13
|
+
const origin = src['gl:origin'];
|
|
14
|
+
if (origin) {
|
|
15
|
+
const ref = origin['gl:ref'];
|
|
16
|
+
if (ref?.['gl:source']) refs.add(ref['gl:source']);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Localized concept-level sources
|
|
21
|
+
for (const lc of Object.values(concept['gl:localizedConcept'] || {})) {
|
|
22
|
+
for (const src of lc['gl:source'] || []) {
|
|
23
|
+
const origin = src['gl:origin'];
|
|
24
|
+
if (origin) {
|
|
25
|
+
const ref = origin['gl:ref'];
|
|
26
|
+
if (ref?.['gl:source']) refs.add(ref['gl:source']);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return [...refs].map(source => ({ source, registerId }));
|
|
32
|
+
}
|