@glossarist/concept-browser 0.7.66 → 0.7.67

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.
Files changed (67) hide show
  1. package/cli/index.mjs +38 -33
  2. package/package.json +2 -2
  3. package/scripts/__tests__/cli-script-contract.test.mjs +39 -0
  4. package/scripts/__tests__/first-non-empty.test.mjs +51 -0
  5. package/scripts/__tests__/process-about-pages.test.mjs +106 -0
  6. package/scripts/build-edges.js +10 -2
  7. package/scripts/fetch-datasets.mjs +61 -54
  8. package/scripts/generate-data.mjs +38 -26
  9. package/scripts/lib/first-non-empty.mjs +19 -0
  10. package/scripts/process-about-pages.mjs +63 -15
  11. package/scripts/validate-shacl.mjs +1 -1
  12. package/src/__tests__/concept-rdf-view.test.ts +21 -13
  13. package/src/__tests__/perf/serialization-perf.test.ts +13 -30
  14. package/src/__tests__/use-rdf-document.test.ts +125 -0
  15. package/src/components/ConceptRdfView.vue +4 -4
  16. package/src/components/use-rdf-document.ts +137 -0
  17. package/src/__tests__/concept-rdf/agents-emitter.test.ts +0 -110
  18. package/src/__tests__/concept-rdf/bibliography-emitter.test.ts +0 -159
  19. package/src/__tests__/concept-rdf/build-activity-emitter.test.ts +0 -119
  20. package/src/__tests__/concept-rdf/coerce-date.test.ts +0 -97
  21. package/src/__tests__/concept-rdf/concept-emitter.test.ts +0 -258
  22. package/src/__tests__/concept-rdf/dataset-emitter.test.ts +0 -224
  23. package/src/__tests__/concept-rdf/differential.test.ts +0 -96
  24. package/src/__tests__/concept-rdf/group-emitter.test.ts +0 -109
  25. package/src/__tests__/concept-rdf/image-variant-emitter.test.ts +0 -135
  26. package/src/__tests__/concept-rdf/jsonld-writer.test.ts +0 -109
  27. package/src/__tests__/concept-rdf/nonverbal-rep.test.ts +0 -177
  28. package/src/__tests__/concept-rdf/property-based.test.ts +0 -179
  29. package/src/__tests__/concept-rdf/provenance.test.ts +0 -110
  30. package/src/__tests__/concept-rdf/quad-isomorphism.test.ts +0 -43
  31. package/src/__tests__/concept-rdf/quad-isomorphism.ts +0 -47
  32. package/src/__tests__/concept-rdf/rdf-components.test.ts +0 -145
  33. package/src/__tests__/concept-rdf/rdf-graph.test.ts +0 -115
  34. package/src/__tests__/concept-rdf/round-trip.test.ts +0 -243
  35. package/src/__tests__/concept-rdf/scoped-examples.test.ts +0 -126
  36. package/src/__tests__/concept-rdf/sections-builder.test.ts +0 -94
  37. package/src/__tests__/concept-rdf/shacl-conformance.test.ts +0 -110
  38. package/src/__tests__/concept-rdf/shape-consistency.test.ts +0 -138
  39. package/src/__tests__/concept-rdf/snapshot-generation.test.ts +0 -75
  40. package/src/__tests__/concept-rdf/table-formula-emitter.test.ts +0 -142
  41. package/src/__tests__/concept-rdf/turtle-writer.test.ts +0 -114
  42. package/src/__tests__/concept-rdf/use-rdf-document.test.ts +0 -246
  43. package/src/__tests__/concept-rdf/version-emitter.test.ts +0 -120
  44. package/src/__tests__/concept-rdf/vocabulary-ssot.test.ts +0 -100
  45. package/src/__tests__/perf/bundle-layout.test.ts +0 -50
  46. package/src/components/concept-rdf/agents-emitter.ts +0 -82
  47. package/src/components/concept-rdf/bibliography-emitter.ts +0 -83
  48. package/src/components/concept-rdf/build-activity-emitter.ts +0 -89
  49. package/src/components/concept-rdf/concept-emitter.ts +0 -443
  50. package/src/components/concept-rdf/dataset-emitter.ts +0 -95
  51. package/src/components/concept-rdf/group-emitter.ts +0 -69
  52. package/src/components/concept-rdf/image-variant-emitter.ts +0 -46
  53. package/src/components/concept-rdf/jsonld-writer.ts +0 -82
  54. package/src/components/concept-rdf/predicates.ts +0 -261
  55. package/src/components/concept-rdf/provenance.ts +0 -80
  56. package/src/components/concept-rdf/rdf-graph.ts +0 -211
  57. package/src/components/concept-rdf/sections-builder.ts +0 -62
  58. package/src/components/concept-rdf/table-formula-emitter.ts +0 -101
  59. package/src/components/concept-rdf/turtle-writer.ts +0 -116
  60. package/src/components/concept-rdf/use-rdf-document.ts +0 -72
  61. package/src/components/concept-rdf/version-emitter.ts +0 -65
  62. package/src/components/concept-rdf/vocabulary-emitter.ts +0 -62
  63. /package/src/components/{concept-rdf/RdfInstanceHeader.vue → RdfInstanceHeader.vue} +0 -0
  64. /package/src/components/{concept-rdf/RdfInstanceSection.vue → RdfInstanceSection.vue} +0 -0
  65. /package/src/components/{concept-rdf/RdfPrefixLegend.vue → RdfPrefixLegend.vue} +0 -0
  66. /package/src/components/{concept-rdf/RdfSourcePanel.vue → RdfSourcePanel.vue} +0 -0
  67. /package/src/components/{concept-rdf/rdf-prefixes.ts → rdf-prefixes.ts} +0 -0
@@ -1,110 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { Parser, Store } from 'n3';
3
- import { writeTurtle } from '../../components/concept-rdf/turtle-writer';
4
- import {
5
- agentsFromContributors,
6
- emitAgentsGraph,
7
- } from '../../components/concept-rdf/agents-emitter';
8
-
9
- const FOAF = 'http://xmlns.com/foaf/0.1/';
10
- const PROV = 'http://www.w3.org/ns/prov#';
11
- const DCTERMS = 'http://purl.org/dc/terms/';
12
- const RDF_TYPE = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type';
13
-
14
- function parse(turtle: string): Store {
15
- const parser = new Parser({ format: 'Turtle' });
16
- const store = new Store();
17
- store.addQuads(parser.parse(turtle));
18
- return store;
19
- }
20
-
21
- describe('agentsFromContributors', () => {
22
- it('turns each contributor into an AgentInput with a slugified IRI', () => {
23
- const agents = agentsFromContributors([
24
- { name: 'Ada Lovelace', role: 'Editor', organization: 'Royal Society', email: 'ada@example.org' },
25
- { name: 'Grace Hopper', organization: 'USN' },
26
- ]);
27
- expect(agents.length).toBe(2);
28
- expect(agents[0].agentIri).toBe('https://glossarist.org/agent/ada-lovelace');
29
- expect(agents[1].agentIri).toBe('https://glossarist.org/agent/grace-hopper');
30
- expect(agents[0].role).toBe('Editor');
31
- });
32
-
33
- it('deduplicates organizations by slug', () => {
34
- const result = emitAgentsGraph(agentsFromContributors([
35
- { name: 'Alice', organization: 'ISO' },
36
- { name: 'Bob', organization: 'ISO' },
37
- { name: 'Carol', organization: 'IEC' },
38
- ]));
39
- expect(result.organizationIris.length).toBe(2);
40
- });
41
- });
42
-
43
- describe('emitAgentsGraph — J4 agent records', () => {
44
- it('types each person as foaf:Person, prov:Person, prov:Agent', () => {
45
- const graph = emitAgentsGraph(agentsFromContributors([
46
- { name: 'Ada Lovelace', email: 'ada@example.org' },
47
- ]));
48
- const store = parse(writeTurtle(graph.graph));
49
- const types = store.getObjects('https://glossarist.org/agent/ada-lovelace', RDF_TYPE, null).map(q => q.value);
50
- expect(types).toContain(`${FOAF}Person`);
51
- expect(types).toContain(`${PROV}Person`);
52
- expect(types).toContain(`${PROV}Agent`);
53
- });
54
-
55
- it('records name, email (as mailto IRI), role, and url', () => {
56
- const graph = emitAgentsGraph(agentsFromContributors([
57
- { name: 'Ada Lovelace', role: 'Editor', email: 'ada@example.org', url: 'https://example.org/ada' },
58
- ]));
59
- const store = parse(writeTurtle(graph.graph));
60
- const names = store.getObjects('https://glossarist.org/agent/ada-lovelace', `${FOAF}name`, null).map(q => q.value);
61
- expect(names).toContain('Ada Lovelace');
62
-
63
- const mboxes = store.getObjects('https://glossarist.org/agent/ada-lovelace', `${FOAF}mbox`, null).map(q => q.value);
64
- expect(mboxes).toContain('mailto:ada@example.org');
65
-
66
- const roles = store.getObjects('https://glossarist.org/agent/ada-lovelace', `${DCTERMS}description`, null).map(q => q.value);
67
- expect(roles).toContain('Editor');
68
-
69
- const seeAlso = store.getObjects('https://glossarist.org/agent/ada-lovelace', 'http://www.w3.org/2000/01/rdf-schema#seeAlso', null).map(q => q.value);
70
- expect(seeAlso).toContain('https://example.org/ada');
71
- });
72
-
73
- it('creates a single prov:Organization per unique organization', () => {
74
- const result = emitAgentsGraph(agentsFromContributors([
75
- { name: 'Alice', organization: 'ISO' },
76
- { name: 'Bob', organization: 'ISO' },
77
- ]));
78
- expect(result.organizationIris).toEqual(['https://glossarist.org/org/iso']);
79
-
80
- const store = parse(writeTurtle(result.graph));
81
- const types = store.getObjects('https://glossarist.org/org/iso', RDF_TYPE, null).map(q => q.value);
82
- expect(types).toContain(`${FOAF}Organization`);
83
- expect(types).toContain(`${PROV}Organization`);
84
- expect(types).toContain(`${PROV}Agent`);
85
-
86
- const names = store.getObjects('https://glossarist.org/org/iso', `${FOAF}name`, null).map(q => q.value);
87
- expect(names).toContain('ISO');
88
- });
89
-
90
- it('links every person to their organization via prov:actedOnBehalfOf', () => {
91
- const result = emitAgentsGraph(agentsFromContributors([
92
- { name: 'Alice', organization: 'ISO' },
93
- { name: 'Bob', organization: 'IEC' },
94
- ]));
95
- const store = parse(writeTurtle(result.graph));
96
- const aliceOrg = store.getObjects('https://glossarist.org/agent/alice', `${PROV}actedOnBehalfOf`, null).map(q => q.value);
97
- expect(aliceOrg).toContain('https://glossarist.org/org/iso');
98
- const bobOrg = store.getObjects('https://glossarist.org/agent/bob', `${PROV}actedOnBehalfOf`, null).map(q => q.value);
99
- expect(bobOrg).toContain('https://glossarist.org/org/iec');
100
- });
101
-
102
- it('omits mbox, seeAlso, and actedOnBehalfOf when not provided', () => {
103
- const graph = emitAgentsGraph(agentsFromContributors([{ name: 'Solo' }]));
104
- const store = parse(writeTurtle(graph.graph));
105
- const mbox = store.getObjects('https://glossarist.org/agent/solo', `${FOAF}mbox`, null);
106
- expect(mbox).toHaveLength(0);
107
- const acted = store.getObjects('https://glossarist.org/agent/solo', `${PROV}actedOnBehalfOf`, null);
108
- expect(acted).toHaveLength(0);
109
- });
110
- });
@@ -1,159 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { Parser, Store } from 'n3';
3
- import { writeTurtle } from '../../components/concept-rdf/turtle-writer';
4
- import {
5
- emitBibliographyGraph,
6
- bibliographyEntryIri,
7
- normalizeBibliographyData,
8
- } from '../../components/concept-rdf/bibliography-emitter';
9
-
10
- const FOAF = 'http://xmlns.com/foaf/0.1/';
11
- const DCTERMS = 'http://purl.org/dc/terms/';
12
- const RDF_TYPE = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type';
13
-
14
- function parse(turtle: string): Store {
15
- const parser = new Parser({ format: 'Turtle' });
16
- const store = new Store();
17
- store.addQuads(parser.parse(turtle));
18
- return store;
19
- }
20
-
21
- describe('emitBibliographyGraph — K5 bibliography graph', () => {
22
- it('types each entry as dcterms:BibliographicResource', () => {
23
- const graph = emitBibliographyGraph({
24
- registerId: 'iso-geodetic',
25
- entries: [{ id: 'iso-704', reference: 'ISO 704' }],
26
- });
27
- const store = parse(writeTurtle(graph));
28
- const iri = bibliographyEntryIri('iso-geodetic', 'iso-704');
29
- const types = store.getObjects(iri, RDF_TYPE, null).map(q => q.value);
30
- expect(types).toContain(`${DCTERMS}BibliographicResource`);
31
- });
32
-
33
- it('emits identifier, bibliographicCitation, and title as literals', () => {
34
- const graph = emitBibliographyGraph({
35
- registerId: 'iso-geodetic',
36
- entries: [
37
- { id: 'iso-704', reference: 'ISO 704', title: 'Terminology work — Principles and methods' },
38
- ],
39
- });
40
- const store = parse(writeTurtle(graph));
41
- const iri = bibliographyEntryIri('iso-geodetic', 'iso-704');
42
- const ids = store.getObjects(iri, `${DCTERMS}identifier`, null).map(q => q.value);
43
- expect(ids).toContain('iso-704');
44
- const cites = store.getObjects(iri, `${DCTERMS}bibliographicCitation`, null).map(q => q.value);
45
- expect(cites).toContain('ISO 704');
46
- const titles = store.getObjects(iri, `${DCTERMS}title`, null).map(q => q.value);
47
- expect(titles).toContain('Terminology work — Principles and methods');
48
- });
49
-
50
- it('emits foaf:page when link is provided', () => {
51
- const graph = emitBibliographyGraph({
52
- registerId: 'iso-geodetic',
53
- entries: [{ id: 'ref', reference: 'X', link: 'https://example.org/x' }],
54
- });
55
- const store = parse(writeTurtle(graph));
56
- const iri = bibliographyEntryIri('iso-geodetic', 'ref');
57
- const pages = store.getObjects(iri, `${FOAF}page`, null).map(q => q.value);
58
- expect(pages).toContain('https://example.org/x');
59
- });
60
-
61
- it('omits foaf:page when link is absent', () => {
62
- const graph = emitBibliographyGraph({
63
- registerId: 'iso-geodetic',
64
- entries: [{ id: 'no-link', reference: 'Y' }],
65
- });
66
- const store = parse(writeTurtle(graph));
67
- const iri = bibliographyEntryIri('iso-geodetic', 'no-link');
68
- const pages = store.getObjects(iri, `${FOAF}page`, null);
69
- expect(pages).toHaveLength(0);
70
- });
71
-
72
- it('emits one resource per entry', () => {
73
- const graph = emitBibliographyGraph({
74
- registerId: 'iso-geodetic',
75
- entries: [
76
- { id: 'a', reference: 'A' },
77
- { id: 'b', reference: 'B' },
78
- { id: 'c', reference: 'C' },
79
- ],
80
- });
81
- const iriA = bibliographyEntryIri('iso-geodetic', 'a');
82
- const iriB = bibliographyEntryIri('iso-geodetic', 'b');
83
- const iriC = bibliographyEntryIri('iso-geodetic', 'c');
84
- const store = parse(writeTurtle(graph));
85
- expect(store.getObjects(iriA, `${DCTERMS}bibliographicCitation`, null).map(q => q.value)).toContain('A');
86
- expect(store.getObjects(iriB, `${DCTERMS}bibliographicCitation`, null).map(q => q.value)).toContain('B');
87
- expect(store.getObjects(iriC, `${DCTERMS}bibliographicCitation`, null).map(q => q.value)).toContain('C');
88
- });
89
-
90
- it('links each entry to the dataset via dcterms:isPartOf', () => {
91
- const graph = emitBibliographyGraph({
92
- registerId: 'iso-geodetic',
93
- entries: [{ id: 'a', reference: 'A' }],
94
- });
95
- const store = parse(writeTurtle(graph));
96
- const iri = bibliographyEntryIri('iso-geodetic', 'a');
97
- const parts = store.getObjects(iri, `${DCTERMS}isPartOf`, null).map(q => q.value);
98
- expect(parts).toContain('https://glossarist.org/iso-geodetic/');
99
- });
100
- });
101
-
102
- describe('B3/C — V3 bibliography shape (wrapper key)', () => {
103
- it('normalizeBibliographyData unwraps { bibliography: [...] } V3 shape', () => {
104
- const v3 = {
105
- bibliography: [
106
- { id: 'iso704', reference: 'ISO 704', title: 'Terminology work', type: 'normative' },
107
- { id: 'iso10241', reference: 'ISO 10241-1' },
108
- ],
109
- };
110
- const entries = normalizeBibliographyData(v3);
111
- expect(entries.length).toBe(2);
112
- expect(entries[0].id).toBe('iso704');
113
- expect(entries[0].type).toBe('normative');
114
- expect(entries[1].id).toBe('iso10241');
115
- });
116
-
117
- it('normalizeBibliographyData accepts the legacy flat-map shape', () => {
118
- const legacy = {
119
- iso704: { reference: 'ISO 704', title: 'Terminology work' },
120
- iso10241: { reference: 'ISO 10241-1' },
121
- };
122
- const entries = normalizeBibliographyData(legacy);
123
- expect(entries.length).toBe(2);
124
- expect(entries.find(e => e.id === 'iso704')?.title).toBe('Terminology work');
125
- });
126
-
127
- it('emitBibliographyGraph handles both V3 and legacy shapes identically', () => {
128
- const v3 = { bibliography: [{ id: 'iso704', reference: 'ISO 704', title: 'T' }] };
129
- const legacy = { iso704: { reference: 'ISO 704', title: 'T' } };
130
-
131
- const graphV3 = emitBibliographyGraph({
132
- registerId: 'r',
133
- entries: normalizeBibliographyData(v3),
134
- });
135
- const graphLegacy = emitBibliographyGraph({
136
- registerId: 'r',
137
- entries: normalizeBibliographyData(legacy),
138
- });
139
-
140
- const storeV3 = parse(writeTurtle(graphV3));
141
- const storeLegacy = parse(writeTurtle(graphLegacy));
142
-
143
- const iri = bibliographyEntryIri('r', 'iso704');
144
- const v3Titles = storeV3.getObjects(iri, `${DCTERMS}title`, null).map(q => q.value);
145
- const legacyTitles = storeLegacy.getObjects(iri, `${DCTERMS}title`, null).map(q => q.value);
146
- expect(v3Titles).toEqual(legacyTitles);
147
- });
148
-
149
- it('emits dcterms:type when entry.type is provided', () => {
150
- const graph = emitBibliographyGraph({
151
- registerId: 'r',
152
- entries: [{ id: 'a', reference: 'X', type: 'normative' }],
153
- });
154
- const store = parse(writeTurtle(graph));
155
- const iri = bibliographyEntryIri('r', 'a');
156
- const types = store.getObjects(iri, `${DCTERMS}type`, null).map(q => q.value);
157
- expect(types.some(t => t.includes('bibtype/normative'))).toBe(true);
158
- });
159
- });
@@ -1,119 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { Parser, Store } from 'n3';
3
- import { writeTurtle } from '../../components/concept-rdf/turtle-writer';
4
- import { emitBuildActivityGraph, activityIri } from '../../components/concept-rdf/build-activity-emitter';
5
- import type { BuildActivityInput } from '../../components/concept-rdf/build-activity-emitter';
6
-
7
- function makeInput(overrides: Partial<BuildActivityInput> = {}): BuildActivityInput {
8
- return {
9
- runId: '2026-06-28T12-00-00Z',
10
- startedAt: '2026-06-28T12:00:00Z',
11
- endedAt: '2026-06-28T12:05:00Z',
12
- gitSha: 'abc1234',
13
- gitBranch: 'main',
14
- toolId: 'concept-browser',
15
- toolVersion: '0.7.51',
16
- datasetRegisters: ['iso-geodetic', 'iso-10303-2-terms'],
17
- conceptCount: 1234,
18
- associatedAgentIri: 'https://glossarist.org/agent/ci-bot',
19
- ...overrides,
20
- };
21
- }
22
-
23
- function parse(turtle: string): Store {
24
- const parser = new Parser({ format: 'Turtle' });
25
- const store = new Store();
26
- store.addQuads(parser.parse(turtle));
27
- return store;
28
- }
29
-
30
- const expand = (v: string): string => {
31
- if (v.startsWith('prov:')) return `http://www.w3.org/ns/prov#${v.slice(5)}`;
32
- if (v.startsWith('dcterms:')) return `http://purl.org/dc/terms/${v.slice(8)}`;
33
- if (v.startsWith('rdf:')) return `http://www.w3.org/1999/02/22-rdf-syntax-ns#${v.slice(4)}`;
34
- if (v.startsWith('xsd:')) return `http://www.w3.org/2001/XMLSchema#${v.slice(4)}`;
35
- if (v.startsWith('foaf:')) return `http://xmlns.com/foaf/0.1/${v.slice(5)}`;
36
- return v;
37
- };
38
-
39
- describe('emitBuildActivityGraph — J7 build activity records', () => {
40
- it('types the activity as prov:Activity', () => {
41
- const input = makeInput();
42
- const graph = emitBuildActivityGraph(input);
43
- const store = parse(writeTurtle(graph));
44
- const iri = activityIri(input);
45
- const types = store.getObjects(iri, expand('rdf:type'), null).map(q => q.value);
46
- expect(types).toContain(expand('prov:Activity'));
47
- });
48
-
49
- it('records the start and end times', () => {
50
- const input = makeInput();
51
- const graph = emitBuildActivityGraph(input);
52
- const store = parse(writeTurtle(graph));
53
- const iri = activityIri(input);
54
- const generated = store.getObjects(iri, expand('prov:generatedAtTime'), null).map(q => q.value);
55
- expect(generated).toContain('2026-06-28T12:05:00Z');
56
- });
57
-
58
- it('types the tool as prov:SoftwareAgent with version', () => {
59
- const input = makeInput();
60
- const graph = emitBuildActivityGraph(input);
61
- const store = parse(writeTurtle(graph));
62
- const toolIri = `https://glossarist.org/tool/${input.toolId}/${input.toolVersion}`;
63
- const types = store.getObjects(toolIri, expand('rdf:type'), null).map(q => q.value);
64
- expect(types).toContain(expand('prov:SoftwareAgent'));
65
- const version = store.getObjects(toolIri, expand('prov:version'), null).map(q => q.value);
66
- expect(version).toContain(input.toolVersion);
67
- });
68
-
69
- it('records the git commit and the tool as prov:used entities', () => {
70
- const input = makeInput();
71
- const graph = emitBuildActivityGraph(input);
72
- const store = parse(writeTurtle(graph));
73
- const iri = activityIri(input);
74
- const used = store.getObjects(iri, expand('prov:used'), null).map(q => q.value);
75
- expect(used).toContain(`https://glossarist.org/commit/${input.gitSha}`);
76
- expect(used).toContain(`https://glossarist.org/tool/${input.toolId}/${input.toolVersion}`);
77
- });
78
-
79
- it('references every dataset register via prov:used', () => {
80
- const input = makeInput();
81
- const graph = emitBuildActivityGraph(input);
82
- const store = parse(writeTurtle(graph));
83
- const iri = activityIri(input);
84
- const used = store.getObjects(iri, expand('prov:used'), null).map(q => q.value);
85
- for (const register of input.datasetRegisters) {
86
- expect(used).toContain(`https://glossarist.org/${register}/`);
87
- }
88
- });
89
-
90
- it('records the concept count as an xsd:integer literal', () => {
91
- const input = makeInput();
92
- const graph = emitBuildActivityGraph(input);
93
- const store = parse(writeTurtle(graph));
94
- const iri = activityIri(input);
95
- const counts = store.getObjects(iri, 'https://www.glossarist.org/ontologies/conceptCount', null).map(q => q.value);
96
- expect(counts).toContain('1234');
97
- });
98
-
99
- it('associates the CI agent when provided', () => {
100
- const input = makeInput();
101
- const graph = emitBuildActivityGraph(input);
102
- const store = parse(writeTurtle(graph));
103
- const iri = activityIri(input);
104
- const agents = store.getObjects(iri, expand('prov:wasAssociatedWith'), null).map(q => q.value);
105
- expect(agents).toContain(input.associatedAgentIri);
106
-
107
- const agentTypes = store.getObjects(input.associatedAgentIri!, expand('rdf:type'), null).map(q => q.value);
108
- expect(agentTypes).toContain(expand('prov:Agent'));
109
- });
110
-
111
- it('omits the commit entity when gitSha is not provided', () => {
112
- const input = makeInput({ gitSha: undefined, gitBranch: undefined });
113
- const graph = emitBuildActivityGraph(input);
114
- const store = parse(writeTurtle(graph));
115
- const iri = activityIri(input);
116
- const used = store.getObjects(iri, expand('prov:used'), null).map(q => q.value);
117
- expect(used.some(u => u.includes('/commit/'))).toBe(false);
118
- });
119
- });
@@ -1,97 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { Parser, Store } from 'n3';
3
- import { Concept } from 'glossarist';
4
- import { writeTurtle } from '../../components/concept-rdf/turtle-writer';
5
- import { emitConceptGraph } from '../../components/concept-rdf/concept-emitter';
6
-
7
- const G = 'https://www.glossarist.org/ontologies/';
8
- const XSD = 'http://www.w3.org/2001/XMLSchema#';
9
-
10
- function parse(turtle: string): Store {
11
- const parser = new Parser({ format: 'Turtle' });
12
- const store = new Store();
13
- store.addQuads(parser.parse(turtle));
14
- return store;
15
- }
16
-
17
- const BASE = 'https://glossarist.org/fixtures/dates';
18
-
19
- describe('B4/C — coerceToDateTime handles year-only and month-only dates', () => {
20
- it('coerces yyyy-mm-dd to xsd:dateTime unchanged (with T00:00:00Z)', () => {
21
- const concept = Concept.fromJSON({
22
- id: 'd.1', uri: `${BASE}/d.1`, status: 'valid',
23
- dates: [{ type: 'accepted', date: '2020-06-15' }],
24
- localizations: {
25
- eng: {
26
- language_code: 'eng', entry_status: 'valid',
27
- terms: [{ type: 'expression', designation: 'd1', normative_status: 'preferred' }],
28
- definition: [{ content: 'def' }],
29
- },
30
- },
31
- });
32
- const { graph } = emitConceptGraph(concept, concept.uri ?? '');
33
- const store = parse(writeTurtle(graph));
34
- const dateBlanks = store.getObjects(concept.uri ?? '', `${G}hasDate`, null);
35
- const values = store.getObjects(dateBlanks[0], `${G}dateValue`, null);
36
- expect((values[0] as any).value).toBe('2020-06-15T00:00:00Z');
37
- expect((values[0] as any).datatype.value).toBe(`${XSD}dateTime`);
38
- });
39
-
40
- it('coerces year-only "2020" to "2020-01-01T00:00:00Z"', () => {
41
- const concept = Concept.fromJSON({
42
- id: 'd.2', uri: `${BASE}/d.2`, status: 'valid',
43
- dates: [{ type: 'accepted', date: '2020' }],
44
- localizations: {
45
- eng: {
46
- language_code: 'eng', entry_status: 'valid',
47
- terms: [{ type: 'expression', designation: 'd2', normative_status: 'preferred' }],
48
- definition: [{ content: 'def' }],
49
- },
50
- },
51
- });
52
- const { graph } = emitConceptGraph(concept, concept.uri ?? '');
53
- const store = parse(writeTurtle(graph));
54
- const dateBlanks = store.getObjects(concept.uri ?? '', `${G}hasDate`, null);
55
- const values = store.getObjects(dateBlanks[0], `${G}dateValue`, null);
56
- expect((values[0] as any).value).toBe('2020-01-01T00:00:00Z');
57
- expect((values[0] as any).datatype.value).toBe(`${XSD}dateTime`);
58
- });
59
-
60
- it('coerces month-only "2020-06" to "2020-06-01T00:00:00Z"', () => {
61
- const concept = Concept.fromJSON({
62
- id: 'd.3', uri: `${BASE}/d.3`, status: 'valid',
63
- dates: [{ type: 'accepted', date: '2020-06' }],
64
- localizations: {
65
- eng: {
66
- language_code: 'eng', entry_status: 'valid',
67
- terms: [{ type: 'expression', designation: 'd3', normative_status: 'preferred' }],
68
- definition: [{ content: 'def' }],
69
- },
70
- },
71
- });
72
- const { graph } = emitConceptGraph(concept, concept.uri ?? '');
73
- const store = parse(writeTurtle(graph));
74
- const dateBlanks = store.getObjects(concept.uri ?? '', `${G}hasDate`, null);
75
- const values = store.getObjects(dateBlanks[0], `${G}dateValue`, null);
76
- expect((values[0] as any).value).toBe('2020-06-01T00:00:00Z');
77
- });
78
-
79
- it('passes through ISO 8601 datetimes unchanged', () => {
80
- const concept = Concept.fromJSON({
81
- id: 'd.4', uri: `${BASE}/d.4`, status: 'valid',
82
- dates: [{ type: 'accepted', date: '2020-06-15T13:45:30Z' }],
83
- localizations: {
84
- eng: {
85
- language_code: 'eng', entry_status: 'valid',
86
- terms: [{ type: 'expression', designation: 'd4', normative_status: 'preferred' }],
87
- definition: [{ content: 'def' }],
88
- },
89
- },
90
- });
91
- const { graph } = emitConceptGraph(concept, concept.uri ?? '');
92
- const store = parse(writeTurtle(graph));
93
- const dateBlanks = store.getObjects(concept.uri ?? '', `${G}hasDate`, null);
94
- const values = store.getObjects(dateBlanks[0], `${G}dateValue`, null);
95
- expect((values[0] as any).value).toBe('2020-06-15T13:45:30Z');
96
- });
97
- });