@glossarist/concept-browser 0.7.87 → 0.7.88
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glossarist/concept-browser",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.88",
|
|
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": {
|
|
@@ -103,4 +103,33 @@ describe('UriRouter', () => {
|
|
|
103
103
|
expect(UriRouter.parseUri('https://example.com/other')).toBeNull();
|
|
104
104
|
});
|
|
105
105
|
});
|
|
106
|
+
|
|
107
|
+
describe('SSOT: UriRouter.buildConceptUri is the single concept-URI constructor', () => {
|
|
108
|
+
// Per AUDIT-2026-07-29 P1-1: ConceptIdentity, the conceptUri()
|
|
109
|
+
// bridge, and UriRouter.buildConceptUri must all funnel through
|
|
110
|
+
// UriRouter.buildConceptUri. No inline template literals for
|
|
111
|
+
// `${uriBase}/${registerId}/concept/${id}` outside UriRouter.
|
|
112
|
+
|
|
113
|
+
it('UriRouter.buildConceptUri constructs the canonical URI', () => {
|
|
114
|
+
expect(UriRouter.buildConceptUri('https://x.org', 'vim', '1.3'))
|
|
115
|
+
.toBe('https://x.org/vim/concept/1.3');
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('UriRouter.buildDomainUri constructs the canonical domain URI', () => {
|
|
119
|
+
expect(UriRouter.buildDomainUri('https://x.org', 'vim', 'physics'))
|
|
120
|
+
.toBe('https://x.org/vim/domain/physics');
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('ConceptIdentity.uri delegates to UriRouter.buildConceptUri', async () => {
|
|
124
|
+
const { ConceptIdentity } = await import('../adapters/concept-identity');
|
|
125
|
+
const id = new ConceptIdentity('1.3', 'vim', 'https://x.org');
|
|
126
|
+
expect(id.uri).toBe(UriRouter.buildConceptUri('https://x.org', 'vim', '1.3'));
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('ConceptIdentity.domainUri delegates to UriRouter.buildDomainUri', async () => {
|
|
130
|
+
const { ConceptIdentity } = await import('../adapters/concept-identity');
|
|
131
|
+
const id = new ConceptIdentity('1.3', 'vim', 'https://x.org');
|
|
132
|
+
expect(id.domainUri('physics')).toBe(UriRouter.buildDomainUri('https://x.org', 'vim', 'physics'));
|
|
133
|
+
});
|
|
134
|
+
});
|
|
106
135
|
});
|
|
@@ -137,7 +137,7 @@ export class GraphDataSource {
|
|
|
137
137
|
if (lc?.domain) {
|
|
138
138
|
edges.push({
|
|
139
139
|
source: sourceUri,
|
|
140
|
-
target:
|
|
140
|
+
target: UriRouter.buildDomainUri(this.uriBase, this.registerId, slugify(lc.domain)),
|
|
141
141
|
type: 'domain',
|
|
142
142
|
label: lc.domain,
|
|
143
143
|
register: this.registerId,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { Manifest } from './types';
|
|
2
|
-
import { ConceptIdentity } from './concept-identity';
|
|
3
2
|
|
|
4
3
|
// ── URI pattern matching ────────────────────────────────────────────────────
|
|
5
4
|
|
|
@@ -106,11 +105,16 @@ export class UriRouter {
|
|
|
106
105
|
return `${uriBase}/${registerId}/concept/${conceptId}`;
|
|
107
106
|
}
|
|
108
107
|
|
|
109
|
-
/** Construct a canonical URI
|
|
108
|
+
/** Construct a canonical domain URI from components. */
|
|
109
|
+
static buildDomainUri(uriBase: string, registerId: string, domainSlug: string): string {
|
|
110
|
+
return `${uriBase}/${registerId}/domain/${domainSlug}`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Construct a canonical URI for a concept from its register-id + concept-id. */
|
|
110
114
|
buildUri(registerId: string, conceptId: string): string {
|
|
111
115
|
const info = this.registerMap.get(registerId);
|
|
112
116
|
const uriBase = info?.uriBase ?? '';
|
|
113
|
-
return
|
|
117
|
+
return UriRouter.buildConceptUri(uriBase, registerId, conceptId);
|
|
114
118
|
}
|
|
115
119
|
|
|
116
120
|
getRegisteredIds(): string[] {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { InvalidConceptIdentityError, InvalidConceptUriError } from '../errors';
|
|
2
|
+
import { UriRouter } from './UriRouter';
|
|
2
3
|
|
|
3
4
|
export interface ConceptIdentityParts {
|
|
4
5
|
readonly localId: string;
|
|
@@ -24,7 +25,10 @@ export class ConceptIdentity implements ConceptIdentityParts {
|
|
|
24
25
|
{ localId, registerId, uriBase },
|
|
25
26
|
);
|
|
26
27
|
}
|
|
27
|
-
|
|
28
|
+
// Single SSOT for concept URI construction: UriRouter.buildConceptUri.
|
|
29
|
+
// ConceptIdentity, the conceptUri() bridge, and UriRouter.buildConceptUri
|
|
30
|
+
// all funnel here — no inline template literals scattered across files.
|
|
31
|
+
this._uri = UriRouter.buildConceptUri(uriBase, registerId, localId);
|
|
28
32
|
this._slug = localId;
|
|
29
33
|
this._path = `${registerId}/concepts/${localId}`;
|
|
30
34
|
}
|
|
@@ -52,7 +56,7 @@ export class ConceptIdentity implements ConceptIdentityParts {
|
|
|
52
56
|
}
|
|
53
57
|
|
|
54
58
|
domainUri(domainSlug: string): string {
|
|
55
|
-
return
|
|
59
|
+
return UriRouter.buildDomainUri(this.uriBase, this.registerId, domainSlug);
|
|
56
60
|
}
|
|
57
61
|
|
|
58
62
|
static fromUri(uri: string): ConceptIdentity {
|
|
@@ -224,6 +224,12 @@ declare module 'glossarist' {
|
|
|
224
224
|
// Re-declare the same exports under the 'glossarist/models' subpath so
|
|
225
225
|
// deep-import callers can use them. Upstream's d.ts is stale on this
|
|
226
226
|
// subpath too.
|
|
227
|
+
//
|
|
228
|
+
// The duplication between the 'glossarist' block above and this block
|
|
229
|
+
// is forced by upstream's broken d.ts (PR glossarist/glossarist-js#31).
|
|
230
|
+
// We cannot `export import` from a local namespace because TypeScript
|
|
231
|
+
// requires `declare module` blocks to be self-contained. When upstream
|
|
232
|
+
// ships proper d.ts, DELETE this entire file.
|
|
227
233
|
declare module 'glossarist/models' {
|
|
228
234
|
export type Completeness = 'complete' | 'partial';
|
|
229
235
|
export const COMPLETENESS: { readonly COMPLETE: 'complete'; readonly PARTIAL: 'partial' };
|
|
@@ -252,23 +258,8 @@ declare module 'glossarist/models' {
|
|
|
252
258
|
export function isValidMultiplicity(value: unknown): value is Multiplicity;
|
|
253
259
|
export function multiplicityFromPair(presence: PartitivePresence, count: PartitiveCount): Multiplicity;
|
|
254
260
|
export function pairFromMultiplicity(name: Multiplicity): { presence: PartitivePresence; count: PartitiveCount };
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
constructor(data?: {
|
|
258
|
-
isShared?: boolean;
|
|
259
|
-
is_shared?: boolean;
|
|
260
|
-
isUncertain?: boolean;
|
|
261
|
-
is_uncertain?: boolean;
|
|
262
|
-
sharedType?: ConceptRef;
|
|
263
|
-
shared_type?: ConceptRef;
|
|
264
|
-
});
|
|
265
|
-
readonly isShared: boolean;
|
|
266
|
-
readonly isUncertain: boolean;
|
|
267
|
-
readonly sharedType: ConceptRef | null;
|
|
268
|
-
hasSharedType(): boolean;
|
|
269
|
-
toJSON(): { is_shared: boolean; is_uncertain?: boolean; shared_type?: ReturnType<ConceptRef['toJSON']> };
|
|
270
|
-
static fromJSON(data: Record<string, unknown>): TypeSharedPlurality;
|
|
271
|
-
}
|
|
261
|
+
// (TypeSharedPlurality removed — superseded by presence/count on
|
|
262
|
+
// PartitiveMember per MECE refactor. Was dead code.)
|
|
272
263
|
|
|
273
264
|
// ── PartitiveRelation (glossarist 0.4.26 — MECE presence × count) ─
|
|
274
265
|
|