@glossarist/concept-browser 0.7.114 → 0.7.115
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 +15 -15
- package/cli/index.ts +9 -11
- package/data/concept-model/shapes/glossarist.concept.yaml.schema.json +255 -0
- package/package.json +14 -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.mjs → bridge-to-astro.ts} +2 -4
- package/scripts/{build-edges.js → build-edges.ts} +11 -13
- package/scripts/{check-syntax.mjs → check-syntax.ts} +20 -13
- package/scripts/{fetch-datasets.mjs → fetch-datasets.ts} +2 -2
- package/scripts/{generate-data.mjs → generate-data.ts} +73 -460
- 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/{process-about-pages.mjs → process-about-pages.ts} +1 -1
- package/scripts/{smoke.mjs → smoke.ts} +4 -3
- package/scripts/{validate-shacl.mjs → validate-shacl.ts} +5 -5
- 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__/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 +2 -2
- 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/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/{extract-source-refs.js → extract-source-refs.ts} +0 -0
- /package/scripts/{generate-404.js → generate-404.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
|
@@ -2,46 +2,59 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import yaml from 'js-yaml';
|
|
4
4
|
import { naturalSort, Register, parseMention } from 'glossarist';
|
|
5
|
-
import { loadSiteConfig } from './load-site-config
|
|
6
|
-
import { getGroups } from './lib/concept-groups
|
|
7
|
-
import { consumeDatasetEntities } from './lib/build/non-verbal-consumer
|
|
8
|
-
import { copyImageAssets } from './lib/build/image-assets
|
|
9
|
-
import { buildDatasetTurtle } from './lib/dataset-turtle
|
|
10
|
-
import { buildActivityTurtle } from './lib/build-activity-turtle
|
|
11
|
-
import { buildVocabularyTurtle } from './lib/vocab-turtle
|
|
12
|
-
import { buildAgentsTurtle } from './lib/agents-turtle
|
|
13
|
-
import { buildVersionHistoryTurtle } from './lib/version-turtle
|
|
14
|
-
import { buildBibliographyTurtle } from './lib/bibliography-turtle
|
|
15
|
-
import { ttlLit } from './lib/turtle-escape
|
|
16
|
-
import { firstNonEmpty } from './lib/first-non-empty
|
|
17
|
-
import { normalizeBibliography } from './lib/bibliography
|
|
5
|
+
import { loadSiteConfig } from './load-site-config';
|
|
6
|
+
import { getGroups } from './lib/concept-groups';
|
|
7
|
+
import { consumeDatasetEntities } from './lib/build/non-verbal-consumer';
|
|
8
|
+
import { copyImageAssets } from './lib/build/image-assets';
|
|
9
|
+
import { buildDatasetTurtle } from './lib/dataset-turtle';
|
|
10
|
+
import { buildActivityTurtle } from './lib/build-activity-turtle';
|
|
11
|
+
import { buildVocabularyTurtle } from './lib/vocab-turtle';
|
|
12
|
+
import { buildAgentsTurtle } from './lib/agents-turtle';
|
|
13
|
+
import { buildVersionHistoryTurtle } from './lib/version-turtle';
|
|
14
|
+
import { buildBibliographyTurtle } from './lib/bibliography-turtle';
|
|
15
|
+
import { ttlLit } from './lib/turtle-escape';
|
|
16
|
+
import { firstNonEmpty } from './lib/first-non-empty';
|
|
17
|
+
import { normalizeBibliography } from './lib/bibliography';
|
|
18
|
+
import type {
|
|
19
|
+
HarmonizedConcept,
|
|
20
|
+
YamlManagedConceptDoc,
|
|
21
|
+
YamlManifest,
|
|
22
|
+
YamlBibliographyEntry,
|
|
23
|
+
YamlNewsFrontmatter,
|
|
24
|
+
YamlContentPage,
|
|
25
|
+
} from './lib/yaml-types';
|
|
26
|
+
import { buildConceptUri } from './lib/concept-uri';
|
|
27
|
+
import {
|
|
28
|
+
loadConceptFile,
|
|
29
|
+
readYaml,
|
|
30
|
+
stripHtml,
|
|
31
|
+
splitMultiplicity,
|
|
32
|
+
LEGACY_MULTIPLICITY_MAP,
|
|
33
|
+
LEGACY_CERTAINTY_FROM_AXIS,
|
|
34
|
+
} from './lib/harmonize-concept';
|
|
35
|
+
import {
|
|
36
|
+
termToDesignation,
|
|
37
|
+
defsToJsonLd,
|
|
38
|
+
refToJsonLd,
|
|
39
|
+
localityToJsonLd,
|
|
40
|
+
sourcesToJsonLd,
|
|
41
|
+
refsToJsonLd,
|
|
42
|
+
citationToJsonLd,
|
|
43
|
+
} from './lib/jsonld-emitter';
|
|
44
|
+
import {
|
|
45
|
+
escapeTurtle,
|
|
46
|
+
escapeXml,
|
|
47
|
+
conceptJsonToTurtle,
|
|
48
|
+
conceptJsonToSkosJsonLd,
|
|
49
|
+
conceptJsonToTbx,
|
|
50
|
+
} from './lib/concept-formats';
|
|
18
51
|
|
|
19
52
|
// MECE partitive multiplicity: 2 independent axes (ISO 704:2022).
|
|
20
53
|
// presence × count
|
|
21
54
|
// Legacy 5-value `multiplicity` and 2-value `certainty` map into the
|
|
22
55
|
// 2-axis model — keep emitting them for one release cycle so consumers
|
|
23
56
|
// that still read the legacy fields keep working.
|
|
24
|
-
|
|
25
|
-
compulsory: { presence: 'required', count: 'exactly_one' },
|
|
26
|
-
optional: { presence: 'optional', count: 'exactly_one' },
|
|
27
|
-
compulsory_multiple: { presence: 'required', count: 'multiple' },
|
|
28
|
-
optional_multiple: { presence: 'optional', count: 'multiple' },
|
|
29
|
-
compulsory_at_least_one: { presence: 'required', count: 'at_least_one' },
|
|
30
|
-
};
|
|
31
|
-
const LEGACY_CERTAINTY_FROM_AXIS = {
|
|
32
|
-
required: 'confirmed',
|
|
33
|
-
optional: 'possible',
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
function splitMultiplicity(multiplicity) {
|
|
37
|
-
return multiplicity in LEGACY_MULTIPLICITY_MAP
|
|
38
|
-
? LEGACY_MULTIPLICITY_MAP[multiplicity]
|
|
39
|
-
: { presence: 'required', count: 'exactly_one' };
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function buildConceptUri(uriBase, registerId, conceptId) {
|
|
43
|
-
return `${uriBase}/${registerId}/concept/${conceptId}`;
|
|
44
|
-
}
|
|
57
|
+
// (LEGACY_MULTIPLICITY_MAP and LEGACY_CERTAINTY_FROM_AXIS imported from harmonize-concept.ts)
|
|
45
58
|
|
|
46
59
|
|
|
47
60
|
const __dirname = path.dirname(new URL(import.meta.url).pathname);
|
|
@@ -55,7 +68,7 @@ const DATA = path.join(PUBLIC, 'data');
|
|
|
55
68
|
* No staging, no copy. fetch-datasets.mjs verifies the path is safe.
|
|
56
69
|
* - Otherwise fall back to the standard .datasets/<id>/ staging dir.
|
|
57
70
|
*/
|
|
58
|
-
function datasetDir(ds) {
|
|
71
|
+
function datasetDir(ds: Record<string, any>): string {
|
|
59
72
|
return ds.localPath
|
|
60
73
|
? path.resolve(ROOT, ds.localPath)
|
|
61
74
|
: path.join(ROOT, '.datasets', ds.id);
|
|
@@ -67,57 +80,6 @@ const DS_PALETTE = [
|
|
|
67
80
|
'#0891b2', '#65a30d',
|
|
68
81
|
];
|
|
69
82
|
|
|
70
|
-
function readYaml(filePath) {
|
|
71
|
-
return yaml.load(fs.readFileSync(filePath, 'utf8'));
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/** Strip HTML tags and normalize whitespace for plain-text display. */
|
|
75
|
-
function stripHtml(s) {
|
|
76
|
-
return s.replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').trim();
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function loadConceptFile(filePath) {
|
|
80
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
81
|
-
const docs = yaml.loadAll(content, null, { schema: yaml.DEFAULT_SCHEMA });
|
|
82
|
-
|
|
83
|
-
if (docs.length === 1 && docs[0].termid !== undefined) {
|
|
84
|
-
return docs[0];
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (docs.length >= 1 && docs[0].data && docs[0].data.identifier !== undefined) {
|
|
88
|
-
const mc = docs[0];
|
|
89
|
-
const result = { termid: String(mc.data.identifier) };
|
|
90
|
-
|
|
91
|
-
// Managed concept-level fields
|
|
92
|
-
if (mc.related) result._related = mc.related;
|
|
93
|
-
if (mc.partitive_relations) result._partitiveRelations = mc.partitive_relations;
|
|
94
|
-
if (mc.generic_relations) result._genericRelations = mc.generic_relations;
|
|
95
|
-
if (mc.data.domains) result._domains = mc.data.domains;
|
|
96
|
-
if (mc.dates) result._dates = mc.dates;
|
|
97
|
-
if (mc.sources) result._sources = mc.sources;
|
|
98
|
-
if (mc.status) result._status = mc.status;
|
|
99
|
-
if (mc.schema_version) result._schemaVersion = mc.schema_version;
|
|
100
|
-
if (mc.date_accepted) result._dateAccepted = mc.date_accepted;
|
|
101
|
-
|
|
102
|
-
for (const doc of docs.slice(1)) {
|
|
103
|
-
if (!doc) continue;
|
|
104
|
-
const lang = doc.data?.language_code || doc.language_code;
|
|
105
|
-
if (!lang) continue;
|
|
106
|
-
const lcData = { ...(doc.data || {}) };
|
|
107
|
-
delete lcData.language_code;
|
|
108
|
-
// Merge top-level fields (terms, definition, notes, etc.) into lcData
|
|
109
|
-
for (const key of ['terms', 'definition', 'notes', 'annotations', 'examples', 'sources', 'dates', 'domain', 'references', 'entry_status', 'classification', 'review_type', 'review_date', 'review_decision_date', 'review_decision_event', 'review_status', 'review_decision', 'review_decision_notes', 'lineage_source_similarity', 'release', 'script', 'system']) {
|
|
110
|
-
if (doc[key] !== undefined && lcData[key] === undefined) {
|
|
111
|
-
lcData[key] = doc[key];
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
result[lang] = lcData;
|
|
115
|
-
}
|
|
116
|
-
return result;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return docs[0];
|
|
120
|
-
}
|
|
121
83
|
|
|
122
84
|
function writeJson(filePath, data) {
|
|
123
85
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
@@ -203,167 +165,13 @@ async function writeBuildActivity(conceptCount, datasetRegisters, baseUri) {
|
|
|
203
165
|
console.log(`Emitted build activity record: data/activity/${runId}.ttl`);
|
|
204
166
|
}
|
|
205
167
|
|
|
206
|
-
function termToDesignation(term) {
|
|
207
|
-
const typeMap = {
|
|
208
|
-
expression: 'gl:Expression',
|
|
209
|
-
abbreviation: 'gl:Abbreviation',
|
|
210
|
-
symbol: 'gl:Symbol',
|
|
211
|
-
letter_symbol: 'gl:LetterSymbol',
|
|
212
|
-
'graphical symbol': 'gl:GraphicalSymbol',
|
|
213
|
-
};
|
|
214
|
-
const doc = {
|
|
215
|
-
'@type': typeMap[term.type] || 'gl:Designation',
|
|
216
|
-
'gl:normativeStatus': term.normative_status || 'preferred',
|
|
217
|
-
'gl:term': term.designation,
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
if (term.grammar_info && term.grammar_info.length > 0) {
|
|
221
|
-
doc['gl:grammarInfo'] = term.grammar_info.map(gi => {
|
|
222
|
-
const g = {};
|
|
223
|
-
if (gi.gender) g['gl:gender'] = gi.gender;
|
|
224
|
-
if (gi.number) g['gl:number'] = gi.number;
|
|
225
|
-
for (const pos of ['noun', 'verb', 'adj', 'adverb', 'preposition', 'participle']) {
|
|
226
|
-
if (gi[pos]) g[`gl:${pos}`] = gi[pos];
|
|
227
|
-
}
|
|
228
|
-
return g;
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (term.international !== undefined) doc['gl:international'] = term.international;
|
|
233
|
-
if (term.absent !== undefined) doc['gl:absent'] = term.absent;
|
|
234
|
-
if (term.geographical_area) doc['gl:geographicalArea'] = term.geographical_area;
|
|
235
|
-
if (term.term_type) doc['gl:termType'] = term.term_type;
|
|
236
|
-
if (term.prefix) doc['gl:prefix'] = term.prefix;
|
|
237
|
-
if (term.usage_info) doc['gl:usageInfo'] = term.usage_info;
|
|
238
|
-
if (term.field_of_application) doc['gl:fieldOfApplication'] = term.field_of_application;
|
|
239
|
-
|
|
240
|
-
if (term.acronym !== undefined) doc['gl:acronym'] = term.acronym;
|
|
241
|
-
if (term.initialism !== undefined) doc['gl:initialism'] = term.initialism;
|
|
242
|
-
if (term.truncation !== undefined) doc['gl:truncation'] = term.truncation;
|
|
243
|
-
|
|
244
|
-
if (term.text) doc['gl:text'] = term.text;
|
|
245
|
-
if (term.image) doc['gl:image'] = term.image;
|
|
246
|
-
|
|
247
|
-
if (term.related && term.related.length > 0) {
|
|
248
|
-
doc['gl:related'] = term.related.map(r => {
|
|
249
|
-
const rel = {};
|
|
250
|
-
if (r.type) rel['gl:relationshipType'] = r.type;
|
|
251
|
-
if (r.target) {
|
|
252
|
-
rel['gl:target'] = r.target;
|
|
253
|
-
} else if (r.ref) {
|
|
254
|
-
const ref = { '@type': 'gl:ConceptRef' };
|
|
255
|
-
if (r.ref.source) ref['gl:source'] = r.ref.source;
|
|
256
|
-
if (r.ref.id) ref['gl:id'] = r.ref.id;
|
|
257
|
-
if (r.ref.text) ref['gl:text'] = r.ref.text;
|
|
258
|
-
rel['gl:ref'] = ref;
|
|
259
|
-
}
|
|
260
|
-
return rel;
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
return doc;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
function defsToJsonLd(defs) {
|
|
268
|
-
if (!defs || !Array.isArray(defs)) return [];
|
|
269
|
-
return defs
|
|
270
|
-
.map(d => ({
|
|
271
|
-
'@type': 'gl:DetailedDefinition',
|
|
272
|
-
'gl:content': d.content || '',
|
|
273
|
-
}))
|
|
274
|
-
.filter(d => d['gl:content']);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
function refToJsonLd(ref, typeName = 'gl:Ref') {
|
|
278
|
-
if (!ref) return undefined;
|
|
279
|
-
const refObj = { '@type': typeName };
|
|
280
|
-
if (typeof ref === 'string') {
|
|
281
|
-
refObj['gl:source'] = ref;
|
|
282
|
-
} else {
|
|
283
|
-
if (ref.source) refObj['gl:source'] = ref.source;
|
|
284
|
-
if (ref.id) refObj['gl:id'] = ref.id;
|
|
285
|
-
if (ref.version) refObj['gl:version'] = ref.version;
|
|
286
|
-
if (ref.text) refObj['gl:text'] = ref.text;
|
|
287
|
-
}
|
|
288
|
-
return refObj;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
function localityToJsonLd(loc) {
|
|
292
|
-
if (!loc) return undefined;
|
|
293
|
-
const locObj = {};
|
|
294
|
-
if (loc.type) locObj['gl:localityType'] = loc.type;
|
|
295
|
-
if (loc.reference_from) locObj['gl:referenceFrom'] = loc.reference_from;
|
|
296
|
-
if (loc.referenceFrom) locObj['gl:referenceFrom'] = loc.referenceFrom;
|
|
297
|
-
if (loc.reference_to) locObj['gl:referenceTo'] = loc.reference_to;
|
|
298
|
-
if (loc.referenceTo) locObj['gl:referenceTo'] = loc.referenceTo;
|
|
299
|
-
return Object.keys(locObj).length > 0 ? locObj : undefined;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
function sourcesToJsonLd(sources) {
|
|
303
|
-
if (!sources || !Array.isArray(sources)) return [];
|
|
304
|
-
return sources.map(s => {
|
|
305
|
-
const doc = { '@type': 'gl:ConceptSource' };
|
|
306
|
-
if (s.id) doc['gl:id'] = s.id;
|
|
307
|
-
if (s.type) doc['gl:sourceType'] = s.type;
|
|
308
|
-
if (s.status) doc['gl:sourceStatus'] = s.status;
|
|
309
|
-
if (s.modification) doc['gl:modification'] = s.modification;
|
|
310
|
-
if (s.origin) {
|
|
311
|
-
const origin = { '@type': 'gl:Citation' };
|
|
312
|
-
const ref = refToJsonLd(s.origin.ref);
|
|
313
|
-
if (ref) origin['gl:ref'] = ref;
|
|
314
|
-
const loc = localityToJsonLd(s.origin.locality);
|
|
315
|
-
if (loc) origin['gl:locality'] = loc;
|
|
316
|
-
if (s.origin.link) origin['gl:link'] = s.origin.link;
|
|
317
|
-
doc['gl:origin'] = origin;
|
|
318
|
-
}
|
|
319
|
-
if (s.sourced_from && s.sourced_from.length) {
|
|
320
|
-
doc['gl:sourcedFrom'] = s.sourced_from.map(sf => {
|
|
321
|
-
const cite = { '@type': 'gl:Citation' };
|
|
322
|
-
const ref = refToJsonLd(sf.ref);
|
|
323
|
-
if (ref) cite['gl:ref'] = ref;
|
|
324
|
-
const loc = localityToJsonLd(sf.locality);
|
|
325
|
-
if (loc) cite['gl:locality'] = loc;
|
|
326
|
-
if (sf.link) cite['gl:link'] = sf.link;
|
|
327
|
-
return cite;
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
return doc;
|
|
331
|
-
});
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
function refsToJsonLd(refs, refMaps) {
|
|
335
|
-
if (!refs || !Array.isArray(refs)) return [];
|
|
336
|
-
return refs.map(r => {
|
|
337
|
-
if (r.id) {
|
|
338
|
-
const ref = { '@id': r.id, 'gl:term': r.term };
|
|
339
|
-
if (r.sourceId) ref['gl:sourceId'] = r.sourceId;
|
|
340
|
-
if (r.citation) ref['gl:citation'] = citationToJsonLd(r.citation);
|
|
341
|
-
return ref;
|
|
342
|
-
}
|
|
343
|
-
if (r.term && refMaps) {
|
|
344
|
-
const uri = resolveRefUri(r.term, refMaps);
|
|
345
|
-
if (uri) return { '@id': uri, 'gl:term': r.term };
|
|
346
|
-
}
|
|
347
|
-
return { '@id': r.id || r.term, 'gl:term': r.term };
|
|
348
|
-
}).filter(r => r['@id']);
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
function citationToJsonLd(citation) {
|
|
352
|
-
const obj = {};
|
|
353
|
-
const ref = refToJsonLd(citation.ref);
|
|
354
|
-
if (ref) obj['gl:ref'] = ref;
|
|
355
|
-
const loc = localityToJsonLd(citation.locality);
|
|
356
|
-
if (loc) obj['gl:locality'] = loc;
|
|
357
|
-
if (citation.link) obj['gl:link'] = citation.link;
|
|
358
|
-
return obj;
|
|
359
|
-
}
|
|
360
168
|
|
|
361
|
-
function buildPatternIndex(datasets, registerCache) {
|
|
362
|
-
const entries = [];
|
|
169
|
+
function buildPatternIndex(datasets: Record<string, any>[], registerCache: Record<string, any>) {
|
|
170
|
+
const entries: { prefix: string; datasetId: string }[] = [];
|
|
363
171
|
|
|
364
172
|
for (const ds of datasets) {
|
|
365
|
-
const reg = registerCache[ds.id] || null;
|
|
366
|
-
const patterns = new Set();
|
|
173
|
+
const reg: Record<string, any> | null = registerCache[ds.id] || null;
|
|
174
|
+
const patterns = new Set<string>();
|
|
367
175
|
|
|
368
176
|
// Site-config patterns (primary)
|
|
369
177
|
if (ds.uri) patterns.add(ds.uri);
|
|
@@ -371,12 +179,12 @@ function buildPatternIndex(datasets, registerCache) {
|
|
|
371
179
|
|
|
372
180
|
// Register.yaml patterns (supplementary)
|
|
373
181
|
if (reg) {
|
|
374
|
-
if (reg.urn && reg.urn.endsWith('*')) patterns.add(reg.urn);
|
|
182
|
+
if (reg.urn && typeof reg.urn === 'string' && reg.urn.endsWith('*')) patterns.add(reg.urn);
|
|
375
183
|
for (const alias of reg.urnAliases || []) patterns.add(alias);
|
|
376
184
|
}
|
|
377
185
|
|
|
378
186
|
for (const pattern of patterns) {
|
|
379
|
-
if (!pattern.endsWith('*')) continue;
|
|
187
|
+
if (typeof pattern !== 'string' || !pattern.endsWith('*')) continue;
|
|
380
188
|
const prefix = pattern.slice(0, -1);
|
|
381
189
|
if (prefix) entries.push({ prefix, datasetId: ds.id });
|
|
382
190
|
}
|
|
@@ -834,201 +642,6 @@ function getPrimaryDesignation(conceptYaml) {
|
|
|
834
642
|
return descs;
|
|
835
643
|
}
|
|
836
644
|
|
|
837
|
-
function escapeTurtle(s) {
|
|
838
|
-
return ttlLit(s).slice(1, -1);
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
function conceptJsonToTurtle(concept) {
|
|
842
|
-
const uri = concept['@id'] || '';
|
|
843
|
-
const id = concept['gl:identifier'] || '';
|
|
844
|
-
const lines = [
|
|
845
|
-
'@prefix skos: <http://www.w3.org/2004/02/skos/core#> .',
|
|
846
|
-
'@prefix dcterms: <http://purl.org/dc/terms/> .',
|
|
847
|
-
'',
|
|
848
|
-
];
|
|
849
|
-
|
|
850
|
-
const props = [' a skos:Concept'];
|
|
851
|
-
props.push(` skos:notation "${escapeTurtle(id)}"`);
|
|
852
|
-
|
|
853
|
-
for (const [lang, lc] of Object.entries(concept['gl:localizedConcept'] || {})) {
|
|
854
|
-
if (lc['gl:designation']) {
|
|
855
|
-
for (const d of lc['gl:designation']) {
|
|
856
|
-
const term = d['gl:term'];
|
|
857
|
-
if (!term) continue;
|
|
858
|
-
const pred = d['gl:normativeStatus'] === 'preferred' ? 'skos:prefLabel' : 'skos:altLabel';
|
|
859
|
-
props.push(` ${pred} "${escapeTurtle(term)}"@${lang}`);
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
if (lc['gl:definition']) {
|
|
863
|
-
for (const d of lc['gl:definition']) {
|
|
864
|
-
if (d['gl:content']) props.push(` skos:definition "${escapeTurtle(d['gl:content'])}"@${lang}`);
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
if (lc['gl:notes']) {
|
|
868
|
-
for (const d of lc['gl:notes']) {
|
|
869
|
-
if (d['gl:content']) props.push(` skos:scopeNote "${escapeTurtle(d['gl:content'])}"@${lang}`);
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
}
|
|
873
|
-
|
|
874
|
-
lines.push(`<${uri}>`);
|
|
875
|
-
lines.push(props.join(' ;\n'));
|
|
876
|
-
lines.push(' .');
|
|
877
|
-
return lines.join('\n');
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
function conceptJsonToSkosJsonLd(concept) {
|
|
881
|
-
const uri = concept['@id'] || '';
|
|
882
|
-
const id = concept['gl:identifier'] || '';
|
|
883
|
-
|
|
884
|
-
const doc = {
|
|
885
|
-
'@context': {
|
|
886
|
-
skos: 'http://www.w3.org/2004/02/skos/core#',
|
|
887
|
-
dcterms: 'http://purl.org/dc/terms/',
|
|
888
|
-
'@language': { '@container': '@language' },
|
|
889
|
-
},
|
|
890
|
-
'@id': uri,
|
|
891
|
-
'@type': 'skos:Concept',
|
|
892
|
-
'skos:notation': id,
|
|
893
|
-
};
|
|
894
|
-
|
|
895
|
-
const prefLabels = {}, altLabels = {}, definitions = {}, scopeNotes = {};
|
|
896
|
-
for (const [lang, lc] of Object.entries(concept['gl:localizedConcept'] || {})) {
|
|
897
|
-
const descs = lc['gl:designation'] || [];
|
|
898
|
-
const pref = descs.find(d => d['gl:normativeStatus'] === 'preferred' && d['gl:term']);
|
|
899
|
-
const alt = descs.find(d => d['gl:normativeStatus'] !== 'preferred' && d['gl:term']);
|
|
900
|
-
if (pref) prefLabels[lang] = pref['gl:term'];
|
|
901
|
-
if (alt) altLabels[lang] = alt['gl:term'];
|
|
902
|
-
const def = (lc['gl:definition'] || [])[0];
|
|
903
|
-
if (def?.['gl:content']) definitions[lang] = def['gl:content'];
|
|
904
|
-
const note = (lc['gl:notes'] || [])[0];
|
|
905
|
-
if (note?.['gl:content']) scopeNotes[lang] = note['gl:content'];
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
if (Object.keys(prefLabels).length) doc['skos:prefLabel'] = prefLabels;
|
|
909
|
-
if (Object.keys(altLabels).length) doc['skos:altLabel'] = altLabels;
|
|
910
|
-
if (Object.keys(definitions).length) doc['skos:definition'] = definitions;
|
|
911
|
-
if (Object.keys(scopeNotes).length) doc['skos:scopeNote'] = scopeNotes;
|
|
912
|
-
|
|
913
|
-
return JSON.stringify(doc);
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
function escapeXml(s) {
|
|
917
|
-
const str = Array.isArray(s) ? s.join(', ') : String(s ?? '');
|
|
918
|
-
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
919
|
-
}
|
|
920
|
-
|
|
921
|
-
function conceptJsonToTbx(concept) {
|
|
922
|
-
const id = concept['gl:identifier'] || '';
|
|
923
|
-
const uri = concept['@id'] || '';
|
|
924
|
-
const localized = concept['gl:localizedConcept'] || {};
|
|
925
|
-
|
|
926
|
-
const langSections = [];
|
|
927
|
-
for (const [lang, lc] of Object.entries(localized)) {
|
|
928
|
-
const descs = lc['gl:designation'] || [];
|
|
929
|
-
const definitions = (lc['gl:definition'] || []).filter(d => d['gl:content']);
|
|
930
|
-
const notes = (lc['gl:notes'] || []).filter(d => d['gl:content']);
|
|
931
|
-
const examples = (lc['gl:examples'] || []).filter(d => d['gl:content']);
|
|
932
|
-
const sources = lc['gl:source'] || [];
|
|
933
|
-
const entryStatus = lc['gl:entryStatus'] || '';
|
|
934
|
-
|
|
935
|
-
if (!descs.length && !definitions.length) continue;
|
|
936
|
-
|
|
937
|
-
const termEntries = [];
|
|
938
|
-
for (const d of descs) {
|
|
939
|
-
const term = d['gl:term'];
|
|
940
|
-
if (!term) continue;
|
|
941
|
-
const status = d['gl:normativeStatus'] || '';
|
|
942
|
-
const type = d['@type'] || '';
|
|
943
|
-
let gramGrp = '';
|
|
944
|
-
if (d['gl:grammarInfo'] && d['gl:grammarInfo'].length > 0) {
|
|
945
|
-
const gi = d['gl:grammarInfo'][0];
|
|
946
|
-
if (gi['gl:gender']) gramGrp = `\n <grammaticalGender>${escapeXml(gi['gl:gender'])}</grammaticalGender>`;
|
|
947
|
-
if (gi['gl:number']) gramGrp += `\n <grammaticalNumber>${escapeXml(gi['gl:number'])}</grammaticalNumber>`;
|
|
948
|
-
for (const pos of ['noun', 'verb', 'adj', 'adverb', 'preposition', 'participle']) {
|
|
949
|
-
if (gi[`gl:${pos}`]) gramGrp += `\n <partOfSpeech>${pos}</partOfSpeech>`;
|
|
950
|
-
}
|
|
951
|
-
}
|
|
952
|
-
let posBlock = '';
|
|
953
|
-
if (type.includes('Abbreviation')) posBlock = '\n <partOfSpeech>abbreviation</partOfSpeech>';
|
|
954
|
-
if (type.includes('Symbol')) posBlock = '\n <partOfSpeech>symbol</partOfSpeech>';
|
|
955
|
-
|
|
956
|
-
termEntries.push(` <termEntry>
|
|
957
|
-
<langSet xml:lang="${lang}">
|
|
958
|
-
<tig>
|
|
959
|
-
<term>${escapeXml(term)}</term>${gramGrp}${posBlock}
|
|
960
|
-
</tig>
|
|
961
|
-
</langSet>
|
|
962
|
-
</termEntry>`);
|
|
963
|
-
}
|
|
964
|
-
|
|
965
|
-
let defBlock = '';
|
|
966
|
-
if (definitions.length) {
|
|
967
|
-
const defParts = definitions.map(d => ` <p>${escapeXml(d['gl:content'])}</p>`).join('\n');
|
|
968
|
-
defBlock = `\n <descrip type="definition">\n${defParts}\n </descrip>`;
|
|
969
|
-
}
|
|
970
|
-
|
|
971
|
-
let noteBlock = '';
|
|
972
|
-
for (let i = 0; i < notes.length; i++) {
|
|
973
|
-
noteBlock += `\n <note type="note">${escapeXml(notes[i]['gl:content'])}</note>`;
|
|
974
|
-
}
|
|
975
|
-
for (let i = 0; i < examples.length; i++) {
|
|
976
|
-
noteBlock += `\n <note type="example">${escapeXml(examples[i]['gl:content'])}</note>`;
|
|
977
|
-
}
|
|
978
|
-
|
|
979
|
-
let sourceBlock = '';
|
|
980
|
-
for (const src of sources) {
|
|
981
|
-
const origin = src['gl:origin'] || {};
|
|
982
|
-
const parts = [];
|
|
983
|
-
const ref = origin['gl:ref'];
|
|
984
|
-
if (ref) {
|
|
985
|
-
const refParts = [];
|
|
986
|
-
if (ref['gl:source']) refParts.push(ref['gl:source']);
|
|
987
|
-
if (ref['gl:id']) refParts.push(ref['gl:id']);
|
|
988
|
-
parts.push(refParts.join(' ') || '');
|
|
989
|
-
}
|
|
990
|
-
if (origin['gl:locality']) {
|
|
991
|
-
const loc = origin['gl:locality'];
|
|
992
|
-
if (loc['gl:referenceFrom']) parts.push(loc['gl:localityType'] ? `${loc['gl:localityType']} ${loc['gl:referenceFrom']}` : loc['gl:referenceFrom']);
|
|
993
|
-
}
|
|
994
|
-
if (parts.filter(Boolean).length) {
|
|
995
|
-
sourceBlock += `\n <ref>${escapeXml(parts.filter(Boolean).join(', '))}</ref>`;
|
|
996
|
-
}
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
let statusBlock = '';
|
|
1000
|
-
if (entryStatus) {
|
|
1001
|
-
statusBlock += `\n <descrip type="entryStatus">${escapeXml(entryStatus)}</descrip>`;
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
const termEntriesBlock = termEntries.length ? '\n' + termEntries.join('\n') : '';
|
|
1005
|
-
langSections.push({ lang, termEntries, blocks: [defBlock, noteBlock, sourceBlock, statusBlock].filter(b => b).join('') });
|
|
1006
|
-
}
|
|
1007
|
-
|
|
1008
|
-
if (!langSections.length) return '';
|
|
1009
|
-
|
|
1010
|
-
const bodyEntries = langSections.map(ls => {
|
|
1011
|
-
return ` <languageSection xml:lang="${ls.lang}">${ls.blocks}\n </languageSection>`;
|
|
1012
|
-
}).join('\n');
|
|
1013
|
-
|
|
1014
|
-
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
1015
|
-
<tbx style="dca" type="TBX-Basic" xml:lang="en" xmlns="urn:iso:std:iso:30042:ed-2">
|
|
1016
|
-
<tbxHeader>
|
|
1017
|
-
<fileDesc>
|
|
1018
|
-
<source>${escapeXml(uri)}</source>
|
|
1019
|
-
</fileDesc>
|
|
1020
|
-
</tbxHeader>
|
|
1021
|
-
<text>
|
|
1022
|
-
<body>
|
|
1023
|
-
<conceptEntry id="${escapeXml(id)}">
|
|
1024
|
-
${bodyEntries}
|
|
1025
|
-
</conceptEntry>
|
|
1026
|
-
</body>
|
|
1027
|
-
</text>
|
|
1028
|
-
</tbx>
|
|
1029
|
-
`;
|
|
1030
|
-
}
|
|
1031
|
-
|
|
1032
645
|
async function processDataset(dir, register, opts) {
|
|
1033
646
|
const files = fs.readdirSync(dir).filter(f => f.endsWith('.yaml')).sort((a, b) => naturalSort(a.replace('.yaml', ''), b.replace('.yaml', '')));
|
|
1034
647
|
|
|
@@ -1052,9 +665,9 @@ async function processDataset(dir, register, opts) {
|
|
|
1052
665
|
if (!conceptYaml?.termid) continue;
|
|
1053
666
|
const termid = String(conceptYaml.termid);
|
|
1054
667
|
for (const lang of Object.keys(conceptYaml)) {
|
|
1055
|
-
const lc = conceptYaml[lang]
|
|
668
|
+
const lc = conceptYaml[lang] as Record<string, any>;
|
|
1056
669
|
if (!lc || typeof lc !== 'object' || !Array.isArray(lc.terms)) continue;
|
|
1057
|
-
for (const term of lc.terms) {
|
|
670
|
+
for (const term of lc.terms as Record<string, any>[]) {
|
|
1058
671
|
const designation = term.designation;
|
|
1059
672
|
if (typeof designation === 'string' && designation && !designationLookup.has(designation.toLowerCase())) {
|
|
1060
673
|
designationLookup.set(designation.toLowerCase(), termid);
|
|
@@ -1171,7 +784,7 @@ async function processDataset(dir, register, opts) {
|
|
|
1171
784
|
id: termid,
|
|
1172
785
|
designations: getPrimaryDesignation(conceptYaml),
|
|
1173
786
|
groups: getGroups(conceptYaml),
|
|
1174
|
-
status: conceptYaml.eng?.entry_status || 'valid',
|
|
787
|
+
status: (conceptYaml.eng as Record<string, any>)?.entry_status || 'valid',
|
|
1175
788
|
});
|
|
1176
789
|
|
|
1177
790
|
for (const processor of STATS_PROCESSORS) {
|
|
@@ -1207,20 +820,20 @@ async function processDataset(dir, register, opts) {
|
|
|
1207
820
|
// Strip HTML from index summary for text display
|
|
1208
821
|
const plainSummary = summary.map(c => {
|
|
1209
822
|
const designations = {};
|
|
1210
|
-
for (const [lang, term] of Object.entries(c.designations)) {
|
|
1211
|
-
if (term) designations[lang] = stripHtml(term);
|
|
823
|
+
for (const [lang, term] of Object.entries(c.designations) as [string, unknown][]) {
|
|
824
|
+
if (term) designations[lang] = stripHtml(String(term));
|
|
1212
825
|
}
|
|
1213
826
|
return {
|
|
1214
827
|
...c,
|
|
1215
828
|
designations,
|
|
1216
|
-
eng: stripHtml(c.eng),
|
|
829
|
+
eng: stripHtml(String(c.eng)),
|
|
1217
830
|
};
|
|
1218
831
|
});
|
|
1219
832
|
|
|
1220
833
|
const graphNodeEntries = concepts.map(c => {
|
|
1221
834
|
const cleanDesignations = {};
|
|
1222
|
-
for (const [l, t] of Object.entries(c.designations)) {
|
|
1223
|
-
if (t) cleanDesignations[l] = stripHtml(t);
|
|
835
|
+
for (const [l, t] of Object.entries(c.designations) as [string, unknown][]) {
|
|
836
|
+
if (t) cleanDesignations[l] = stripHtml(String(t));
|
|
1224
837
|
}
|
|
1225
838
|
return [c.id, cleanDesignations, c.status];
|
|
1226
839
|
});
|
|
@@ -1292,7 +905,7 @@ async function processDataset(dir, register, opts) {
|
|
|
1292
905
|
conceptIds: s.conceptIds,
|
|
1293
906
|
}))
|
|
1294
907
|
.sort((a, b) => b.conceptCount - a.conceptCount);
|
|
1295
|
-
const totalRelationships = Object.values(stats.relTypeCounts).reduce((a, b) => a + b, 0);
|
|
908
|
+
const totalRelationships = Object.values(stats.relTypeCounts).reduce((a: number, b: number) => a + b, 0);
|
|
1296
909
|
|
|
1297
910
|
writeJson(path.join(DATA, register, 'stats.json'), {
|
|
1298
911
|
sourceCount: sourceStats.length,
|
|
@@ -1302,7 +915,7 @@ async function processDataset(dir, register, opts) {
|
|
|
1302
915
|
partitiveRelations: stats.partitiveRelations,
|
|
1303
916
|
});
|
|
1304
917
|
|
|
1305
|
-
const manifest = {
|
|
918
|
+
const manifest: Record<string, any> = {
|
|
1306
919
|
id: register,
|
|
1307
920
|
datasetUri: opts.datasetUri,
|
|
1308
921
|
uriAliases: opts.uriAliases,
|
|
@@ -1571,7 +1184,7 @@ function processNewsPage(config, page) {
|
|
|
1571
1184
|
|
|
1572
1185
|
for (const file of postFiles) {
|
|
1573
1186
|
const content = fs.readFileSync(path.join(newsDir, file), 'utf8');
|
|
1574
|
-
const frontmatter = {};
|
|
1187
|
+
const frontmatter: Record<string, string> = {};
|
|
1575
1188
|
const bodyLines = [];
|
|
1576
1189
|
|
|
1577
1190
|
let inFm = false;
|
|
@@ -1614,20 +1227,20 @@ function processNewsPage(config, page) {
|
|
|
1614
1227
|
|
|
1615
1228
|
// --- Markdown-lite renderer (isomorphic, same logic as src/utils/markdown-lite.ts) ---
|
|
1616
1229
|
|
|
1617
|
-
function renderMarkdown(input) {
|
|
1618
|
-
const INLINE_PATTERNS = [
|
|
1230
|
+
function renderMarkdown(input: string): string {
|
|
1231
|
+
const INLINE_PATTERNS: [RegExp, (m: string[]) => string][] = [
|
|
1619
1232
|
[/\*\*(.+?)\*\*/g, m => `<strong>${m[1]}</strong>`],
|
|
1620
1233
|
[/(?<!\*)\*([^*]+?)\*(?!\*)/g, m => `<em>${m[1]}</em>`],
|
|
1621
1234
|
[/`([^`]+?)`/g, m => `<code>${m[1]}</code>`],
|
|
1622
1235
|
[/\[([^\]]+)\]\(([^)]+)\)/g, m => `<a href="${m[2]}" target="_blank">${m[1]}</a>`],
|
|
1623
1236
|
];
|
|
1624
|
-
function renderInline(text) {
|
|
1237
|
+
function renderInline(text: string): string {
|
|
1625
1238
|
for (const [re, fn] of INLINE_PATTERNS) {
|
|
1626
|
-
text = text.replace(re, (...args) => fn(args));
|
|
1239
|
+
text = text.replace(re, (...args: string[]) => fn(args));
|
|
1627
1240
|
}
|
|
1628
1241
|
return text;
|
|
1629
1242
|
}
|
|
1630
|
-
function escapeHtml(s) {
|
|
1243
|
+
function escapeHtml(s: string): string {
|
|
1631
1244
|
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
1632
1245
|
}
|
|
1633
1246
|
|
|
@@ -1684,7 +1297,7 @@ function renderMarkdown(input) {
|
|
|
1684
1297
|
return blocks.join('\n');
|
|
1685
1298
|
}
|
|
1686
1299
|
|
|
1687
|
-
function processContentPage(config, page) {
|
|
1300
|
+
function processContentPage(config: Record<string, any>, page: Record<string, any>) {
|
|
1688
1301
|
if (!page.source) {
|
|
1689
1302
|
console.warn(` Skipping content page '${page.route}': no source file`);
|
|
1690
1303
|
return;
|
|
@@ -1711,7 +1324,7 @@ function processContentPage(config, page) {
|
|
|
1711
1324
|
|
|
1712
1325
|
// Generate localized versions
|
|
1713
1326
|
if (page.translations) {
|
|
1714
|
-
for (const [lang, tr] of Object.entries(page.translations)) {
|
|
1327
|
+
for (const [lang, tr] of Object.entries(page.translations) as [string, Record<string, any>][]) {
|
|
1715
1328
|
const { source, title: trTitle } = tr;
|
|
1716
1329
|
if (!source) continue;
|
|
1717
1330
|
const trSrcPath = path.resolve(ROOT, source);
|
|
@@ -1873,7 +1486,7 @@ writeJson(path.join(PUBLIC, 'site-config.json'), {
|
|
|
1873
1486
|
});
|
|
1874
1487
|
console.log('Generated site-config.json');
|
|
1875
1488
|
|
|
1876
|
-
const total = Object.values(counts).reduce((s, n) => s + n, 0);
|
|
1489
|
+
const total = Object.values(counts).reduce((s: number, n: number) => s + n, 0);
|
|
1877
1490
|
console.log(`\nDone! Generated data for ${total} concepts across ${registry.length} datasets.`);
|
|
1878
1491
|
for (const [id, count] of Object.entries(counts)) {
|
|
1879
1492
|
console.log(` ${id}: ${count} concepts`);
|
|
@@ -386,8 +386,8 @@ function extractPropertyBlocks(shapeBlock) {
|
|
|
386
386
|
return blocks;
|
|
387
387
|
}
|
|
388
388
|
|
|
389
|
-
function parseConstraint(propBlock) {
|
|
390
|
-
const c = {};
|
|
389
|
+
function parseConstraint(propBlock: string): Record<string, any> {
|
|
390
|
+
const c: Record<string, any> = {};
|
|
391
391
|
const path = extractResource(propBlock, 'sh:path');
|
|
392
392
|
c.path = path ? compactIri(expandPrefixed(path)) : null;
|
|
393
393
|
|