glossarist 0.4.38 → 0.4.40

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 (41) hide show
  1. package/package.json +1 -1
  2. package/src/models/base.ts +18 -1
  3. package/src/models/citation.ts +98 -0
  4. package/src/models/{concept-reference.js → concept-reference.ts} +21 -7
  5. package/src/models/designation-relationship.ts +39 -0
  6. package/src/models/designation.ts +297 -0
  7. package/src/models/figure.ts +110 -0
  8. package/src/models/formula.ts +36 -0
  9. package/src/models/gcr-metadata.ts +118 -0
  10. package/src/models/gcr-statistics.ts +76 -0
  11. package/src/models/hyperedge-colors.ts +87 -0
  12. package/src/models/non-verb-rep.ts +48 -0
  13. package/src/models/non-verbal-entity.ts +65 -0
  14. package/src/models/non-verbal-reference.ts +73 -0
  15. package/src/models/non-verbal-references.ts +29 -0
  16. package/src/models/register.ts +315 -0
  17. package/src/models/registrable.ts +48 -0
  18. package/src/models/{related-concept.js → related-concept.ts} +49 -25
  19. package/src/models/relation-categories.ts +167 -0
  20. package/src/models/{relation-colors.js → relation-colors.ts} +36 -23
  21. package/src/models/section.ts +61 -0
  22. package/src/models/shared-non-verbal-entity.ts +36 -0
  23. package/src/models/table.ts +36 -0
  24. package/src/models/citation.js +0 -68
  25. package/src/models/designation-relationship.js +0 -27
  26. package/src/models/designation.js +0 -213
  27. package/src/models/figure.js +0 -75
  28. package/src/models/formula.js +0 -25
  29. package/src/models/gcr-metadata.js +0 -68
  30. package/src/models/gcr-statistics.js +0 -51
  31. package/src/models/hyperedge-colors.js +0 -71
  32. package/src/models/non-verb-rep.js +0 -33
  33. package/src/models/non-verbal-entity.js +0 -46
  34. package/src/models/non-verbal-reference.js +0 -35
  35. package/src/models/non-verbal-references.js +0 -16
  36. package/src/models/register.js +0 -253
  37. package/src/models/registrable.js +0 -25
  38. package/src/models/relation-categories.js +0 -182
  39. package/src/models/section.js +0 -44
  40. package/src/models/shared-non-verbal-entity.js +0 -28
  41. package/src/models/table.js +0 -25
@@ -0,0 +1,118 @@
1
+ import * as yaml from 'js-yaml';
2
+ import { GlossaristModel } from './base.js';
3
+ import { GcrStatistics } from './gcr-statistics.js';
4
+ import type { GcrStatisticsJson } from './gcr-statistics.js';
5
+
6
+ export interface GcrMetadataJson {
7
+ shortname?: string | null;
8
+ version?: string | null;
9
+ title?: string | null;
10
+ description?: string | null;
11
+ owner?: string | null;
12
+ tags?: ReadonlyArray<string>;
13
+ concept_count?: number;
14
+ conceptCount?: number;
15
+ languages?: ReadonlyArray<string>;
16
+ created_at?: string | null;
17
+ createdAt?: string | null;
18
+ glossarist_version?: string | null;
19
+ glossaristVersion?: string | null;
20
+ schema_version?: string;
21
+ schemaVersion?: string;
22
+ homepage?: string | null;
23
+ repository?: string | null;
24
+ license?: string | null;
25
+ uri_prefix?: string | null;
26
+ uriPrefix?: string | null;
27
+ concept_uri_template?: string | null;
28
+ conceptUriTemplate?: string | null;
29
+ compiled_formats?: ReadonlyArray<string>;
30
+ compiledFormats?: ReadonlyArray<string>;
31
+ statistics?: GcrStatisticsJson | GcrStatistics | null;
32
+ }
33
+
34
+ export class GcrMetadata extends GlossaristModel {
35
+ readonly shortname: string | null;
36
+ readonly version: string | null;
37
+ readonly title: string | null;
38
+ readonly description: string | null;
39
+ readonly owner: string | null;
40
+ readonly tags: ReadonlyArray<string>;
41
+ readonly conceptCount: number;
42
+ readonly languages: ReadonlyArray<string>;
43
+ readonly createdAt: string | null;
44
+ readonly glossaristVersion: string | null;
45
+ readonly schemaVersion: string;
46
+ readonly homepage: string | null;
47
+ readonly repository: string | null;
48
+ readonly license: string | null;
49
+ readonly uriPrefix: string | null;
50
+ readonly conceptUriTemplate: string | null;
51
+ readonly compiledFormats: ReadonlyArray<string>;
52
+ readonly statistics: GcrStatistics | null;
53
+
54
+ constructor(data: GcrMetadataJson = {}) {
55
+ super();
56
+ this.shortname = data.shortname ?? null;
57
+ this.version = data.version ?? null;
58
+ this.title = data.title ?? null;
59
+ this.description = data.description ?? null;
60
+ this.owner = data.owner ?? null;
61
+ this.tags = (data.tags as ReadonlyArray<string>) ?? [];
62
+ this.conceptCount = data.concept_count ?? data.conceptCount ?? 0;
63
+ this.languages = (data.languages as ReadonlyArray<string>) ?? [];
64
+ this.createdAt = data.created_at ?? data.createdAt ?? null;
65
+ this.glossaristVersion = data.glossarist_version ?? data.glossaristVersion ?? null;
66
+ this.schemaVersion = data.schema_version ?? data.schemaVersion ?? '1';
67
+ this.homepage = data.homepage ?? null;
68
+ this.repository = data.repository ?? null;
69
+ this.license = data.license ?? null;
70
+ this.uriPrefix = data.uri_prefix ?? data.uriPrefix ?? null;
71
+ this.conceptUriTemplate = data.concept_uri_template ?? data.conceptUriTemplate ?? null;
72
+ this.compiledFormats = data.compiled_formats ?? data.compiledFormats ?? [];
73
+ this.statistics = data.statistics
74
+ ? data.statistics instanceof GcrStatistics
75
+ ? data.statistics
76
+ : new GcrStatistics(data.statistics as GcrStatisticsJson)
77
+ : null;
78
+ }
79
+
80
+ get concept_count(): number { return this.conceptCount; }
81
+ get created_at(): string | null { return this.createdAt; }
82
+ get glossarist_version(): string | null { return this.glossaristVersion; }
83
+ get schema_version(): string { return this.schemaVersion; }
84
+ get uri_prefix(): string | null { return this.uriPrefix; }
85
+ get concept_uri_template(): string | null { return this.conceptUriTemplate; }
86
+ get compiled_formats(): ReadonlyArray<string> { return this.compiledFormats; }
87
+
88
+ override toJSON(): GcrMetadataJson {
89
+ const obj: GcrMetadataJson = {};
90
+ if (this.shortname != null) obj.shortname = this.shortname;
91
+ if (this.version != null) obj.version = this.version;
92
+ if (this.title != null) obj.title = this.title;
93
+ if (this.description != null) obj.description = this.description;
94
+ if (this.owner != null) obj.owner = this.owner;
95
+ if (this.tags.length > 0) obj.tags = [...this.tags];
96
+ if (this.conceptCount > 0) obj.concept_count = this.conceptCount;
97
+ if (this.languages.length > 0) obj.languages = [...this.languages];
98
+ if (this.createdAt != null) obj.created_at = this.createdAt;
99
+ if (this.glossaristVersion != null) obj.glossarist_version = this.glossaristVersion;
100
+ if (this.schemaVersion != null) obj.schema_version = this.schemaVersion;
101
+ if (this.homepage != null) obj.homepage = this.homepage;
102
+ if (this.repository != null) obj.repository = this.repository;
103
+ if (this.license != null) obj.license = this.license;
104
+ if (this.uriPrefix != null) obj.uri_prefix = this.uriPrefix;
105
+ if (this.conceptUriTemplate != null) obj.concept_uri_template = this.conceptUriTemplate;
106
+ if (this.compiledFormats.length > 0) obj.compiled_formats = [...this.compiledFormats];
107
+ if (this.statistics != null) obj.statistics = this.statistics.toJSON();
108
+ return obj;
109
+ }
110
+
111
+ static override fromJSON(data: GcrMetadataJson): GcrMetadata {
112
+ return new GcrMetadata(data);
113
+ }
114
+
115
+ static fromYaml(yamlString: string): GcrMetadata {
116
+ return new GcrMetadata(yaml.load(yamlString) as GcrMetadataJson);
117
+ }
118
+ }
@@ -0,0 +1,76 @@
1
+ import { GlossaristModel } from './base.js';
2
+
3
+ export interface GcrStatisticsJson {
4
+ total_concepts?: number;
5
+ totalConcepts?: number;
6
+ concepts_with_definitions?: number;
7
+ conceptsWithDefinitions?: number;
8
+ concepts_by_status?: Record<string, number>;
9
+ conceptsByStatus?: Record<string, number>;
10
+ }
11
+
12
+ interface ConceptLike {
13
+ languages: ReadonlyArray<string>;
14
+ localization(lang: string): {
15
+ definitions: ReadonlyArray<unknown>;
16
+ entryStatus?: string | null;
17
+ } | null | undefined;
18
+ }
19
+
20
+ export class GcrStatistics extends GlossaristModel {
21
+ readonly totalConcepts: number;
22
+ readonly conceptsWithDefinitions: number;
23
+ readonly conceptsByStatus: Record<string, number>;
24
+
25
+ constructor(data: GcrStatisticsJson = {}) {
26
+ super();
27
+ this.totalConcepts = data.total_concepts ?? data.totalConcepts ?? 0;
28
+ this.conceptsWithDefinitions =
29
+ data.concepts_with_definitions ?? data.conceptsWithDefinitions ?? 0;
30
+ this.conceptsByStatus =
31
+ (data.concepts_by_status as Record<string, number>) ??
32
+ (data.conceptsByStatus as Record<string, number>) ??
33
+ {};
34
+ }
35
+
36
+ get total_concepts(): number { return this.totalConcepts; }
37
+ get concepts_with_definitions(): number { return this.conceptsWithDefinitions; }
38
+ get concepts_by_status(): Record<string, number> { return this.conceptsByStatus; }
39
+
40
+ override toJSON(): GcrStatisticsJson {
41
+ const obj: GcrStatisticsJson = { total_concepts: this.totalConcepts };
42
+ if (this.conceptsWithDefinitions > 0) {
43
+ obj.concepts_with_definitions = this.conceptsWithDefinitions;
44
+ }
45
+ if (Object.keys(this.conceptsByStatus).length > 0) {
46
+ obj.concepts_by_status = this.conceptsByStatus;
47
+ }
48
+ return obj;
49
+ }
50
+
51
+ static override fromJSON(data: GcrStatisticsJson): GcrStatistics {
52
+ return new GcrStatistics(data);
53
+ }
54
+
55
+ static fromConcepts(concepts: ReadonlyArray<ConceptLike>): GcrStatistics {
56
+ const langs = new Set<string>();
57
+ let withDefs = 0;
58
+ const byStatus: Record<string, number> = {};
59
+
60
+ for (const concept of concepts) {
61
+ for (const lang of concept.languages) {
62
+ langs.add(lang);
63
+ const lc = concept.localization(lang);
64
+ if (lc && lc.definitions.length > 0) withDefs++;
65
+ const status = lc?.entryStatus ?? 'unknown';
66
+ byStatus[status] = (byStatus[status] ?? 0) + 1;
67
+ }
68
+ }
69
+
70
+ return new GcrStatistics({
71
+ total_concepts: concepts.length,
72
+ concepts_with_definitions: withDefs,
73
+ concepts_by_status: byStatus,
74
+ });
75
+ }
76
+ }
@@ -0,0 +1,87 @@
1
+ // Hyperedge color resolver — resolves display colors for a
2
+ // PartitiveHyperedge based on its enumeration and the carrying
3
+ // concept's category color.
4
+
5
+ import { categoryColorPair } from './relation-colors.js';
6
+ import type { ColorPair } from './relation-colors.js';
7
+
8
+ const ENUMERATION_INTENSITY: Readonly<Record<string, number>> = Object.freeze({
9
+ closed: 1.0,
10
+ open: 0.55,
11
+ });
12
+
13
+ const DEFAULT_CATEGORY = 'hierarchical';
14
+
15
+ export interface ResolveHyperedgeColorOptions {
16
+ category?: string;
17
+ overrides?: { byCategory?: Record<string, Partial<ColorPair>> };
18
+ }
19
+
20
+ export interface ResolvedHyperedgeColor {
21
+ light: string;
22
+ dark: string;
23
+ pattern: 'dashed' | 'double' | null;
24
+ }
25
+
26
+ interface HyperedgeLike {
27
+ enumeration?: string;
28
+ markers?: ReadonlyArray<string>;
29
+ }
30
+
31
+ export function resolveHyperedgeColor(
32
+ hyperedge: HyperedgeLike | null,
33
+ options: ResolveHyperedgeColorOptions = {},
34
+ ): ResolvedHyperedgeColor | null {
35
+ if (!hyperedge) return null;
36
+
37
+ const category = options.category ?? DEFAULT_CATEGORY;
38
+ const base = categoryColorPair(category, options.overrides);
39
+ if (!base) return null;
40
+
41
+ const intensity = ENUMERATION_INTENSITY[hyperedge.enumeration ?? ''] ?? 1.0;
42
+ const pattern = derivePattern(hyperedge.markers);
43
+
44
+ return {
45
+ light: tint(base.light, intensity),
46
+ dark: tint(base.dark, intensity),
47
+ pattern,
48
+ };
49
+ }
50
+
51
+ function derivePattern(
52
+ markers: ReadonlyArray<string> | null | undefined,
53
+ ): 'dashed' | 'double' | null {
54
+ const arr = markers ?? [];
55
+ if (arr.includes('dashed')) return 'dashed';
56
+ if (arr.includes('double')) return 'double';
57
+ return null;
58
+ }
59
+
60
+ /**
61
+ * Linear interpolation between the base color and white (light mode)
62
+ * or between the base and a neutral (dark mode). Pure-string inputs
63
+ * return the original color when intensity === 1.0.
64
+ */
65
+ function tint(hex: string, ratio: number): string {
66
+ if (ratio >= 1.0) return hex;
67
+ const rgb = parseHex(hex);
68
+ if (!rgb) return hex;
69
+
70
+ const target: ReadonlyArray<number> = [255, 255, 255];
71
+ const mixed = rgb.map((c, i) =>
72
+ Math.round(c + ((target[i] ?? 255) - c) * (1 - ratio)),
73
+ );
74
+ return '#' + mixed.map((c) => c.toString(16).padStart(2, '0')).join('');
75
+ }
76
+
77
+ function parseHex(s: string): [number, number, number] | null {
78
+ if (typeof s !== 'string') return null;
79
+ const m = s.match(/^#?([0-9a-f]{6})$/i);
80
+ if (!m) return null;
81
+ const n = m[1] as string;
82
+ return [
83
+ parseInt(n.slice(0, 2), 16),
84
+ parseInt(n.slice(2, 4), 16),
85
+ parseInt(n.slice(4, 6), 16),
86
+ ];
87
+ }
@@ -0,0 +1,48 @@
1
+ import { NonVerbalEntity } from './non-verbal-entity.js';
2
+ import type { NonVerbalEntityJson } from './non-verbal-entity.js';
3
+ import { FigureImage } from './figure.js';
4
+ import type { FigureImageJson } from './figure.js';
5
+
6
+ export const NON_VERBAL_TYPES: ReadonlyArray<string> = Object.freeze([
7
+ 'image', 'table', 'formula',
8
+ ]);
9
+
10
+ export interface NonVerbRepJson extends NonVerbalEntityJson {
11
+ type?: string | null;
12
+ images?: ReadonlyArray<FigureImageJson | FigureImage>;
13
+ }
14
+
15
+ export class NonVerbRep extends NonVerbalEntity {
16
+ readonly type: string | null;
17
+ protected readonly _rawImages: ReadonlyArray<FigureImageJson | FigureImage>;
18
+ protected _images: ReadonlyArray<FigureImage> | null = null;
19
+
20
+ constructor(data: NonVerbRepJson = {}) {
21
+ super(data);
22
+ this.type = data.type ?? null;
23
+ this._rawImages = data.images ?? [];
24
+ }
25
+
26
+ override rdfClass(): string {
27
+ return 'NonVerbalRepresentation';
28
+ }
29
+
30
+ get images(): ReadonlyArray<FigureImage> {
31
+ return this._lazy<FigureImage>(
32
+ '_images',
33
+ '_rawImages',
34
+ (i) => (i instanceof FigureImage ? i : new FigureImage(i as FigureImageJson)),
35
+ );
36
+ }
37
+
38
+ override toJSON(): NonVerbRepJson {
39
+ const obj = super.toJSON() as NonVerbRepJson;
40
+ if (this.type != null) obj.type = this.type;
41
+ this._serialize(obj as unknown as Record<string, unknown>, 'images', '_images', '_rawImages');
42
+ return obj;
43
+ }
44
+
45
+ static override fromJSON(data: NonVerbRepJson): NonVerbRep {
46
+ return new NonVerbRep(data);
47
+ }
48
+ }
@@ -0,0 +1,65 @@
1
+ import { RegistrableModel } from './registrable.js';
2
+ import { ConceptSource } from './concept-source.js';
3
+ import type { ConceptSourceJson } from './concept-source.js';
4
+
5
+ export interface NonVerbalEntityJson {
6
+ caption?: string | null;
7
+ description?: string | null;
8
+ alt?: string | null;
9
+ sources?: ReadonlyArray<ConceptSourceJson | ConceptSource>;
10
+ type?: string | null;
11
+ }
12
+
13
+ export class NonVerbalEntity extends RegistrableModel {
14
+ readonly caption: string | null;
15
+ readonly description: string | null;
16
+ readonly alt: string | null;
17
+ protected readonly _rawSources: ReadonlyArray<ConceptSourceJson | ConceptSource>;
18
+ protected _sources: ReadonlyArray<ConceptSource> | null = null;
19
+
20
+ constructor(data: NonVerbalEntityJson = {}) {
21
+ super();
22
+ this.caption = data.caption ?? null;
23
+ this.description = data.description ?? null;
24
+ this.alt = data.alt ?? null;
25
+ this._rawSources = data.sources ?? [];
26
+ }
27
+
28
+ get sources(): ReadonlyArray<ConceptSource> {
29
+ return this._lazy<ConceptSource>(
30
+ '_sources',
31
+ '_rawSources',
32
+ (s) => (s instanceof ConceptSource ? s : new ConceptSource(s as ConceptSourceJson)),
33
+ );
34
+ }
35
+
36
+ /**
37
+ * Ontology class local-name. Subtypes override to return their specific
38
+ * class (Figure/Table/Formula). Used by the RDF emitter so a new subtype
39
+ * registers without editing the emitter (OCP).
40
+ */
41
+ rdfClass(): string {
42
+ return 'NonVerbalEntity';
43
+ }
44
+
45
+ findById(_targetId: string): NonVerbalEntity | null {
46
+ return null;
47
+ }
48
+
49
+ allIds(): string[] {
50
+ return [];
51
+ }
52
+
53
+ override toJSON(): NonVerbalEntityJson {
54
+ const obj: NonVerbalEntityJson = {};
55
+ if (this.caption != null) obj.caption = this.caption;
56
+ if (this.description != null) obj.description = this.description;
57
+ if (this.alt != null) obj.alt = this.alt;
58
+ this._serialize(obj as unknown as Record<string, unknown>, 'sources', '_sources', '_rawSources');
59
+ return obj;
60
+ }
61
+
62
+ static override fromJSON(data: NonVerbalEntityJson): NonVerbalEntity {
63
+ return NonVerbalEntity.fromData(data);
64
+ }
65
+ }
@@ -0,0 +1,73 @@
1
+ import { RegistrableModel } from './registrable.js';
2
+
3
+ export interface NonVerbalReferenceJson {
4
+ entityId?: string | null;
5
+ entity_id?: string | null;
6
+ ref?: string | null;
7
+ id?: string | null;
8
+ display?: string | null;
9
+ type?: string;
10
+ }
11
+
12
+ /**
13
+ * Polymorphic JSON for NonVerbalReference: either a bare string (the
14
+ * entity id) or an object with `{ ref, display?, type? }`.
15
+ */
16
+ export type NonVerbalReferenceInput =
17
+ | NonVerbalReferenceJson
18
+ | string
19
+ | NonVerbalReference;
20
+
21
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
+ type AnyCtor = new (...args: any[]) => any;
23
+
24
+ export class NonVerbalReference extends RegistrableModel {
25
+ readonly entityId: string | null;
26
+ readonly display: string | null;
27
+
28
+ constructor(data: NonVerbalReferenceJson = {}) {
29
+ super();
30
+ this.entityId = data.entityId ?? data.entity_id ?? data.ref ?? data.id ?? null;
31
+ this.display = data.display ?? null;
32
+ }
33
+
34
+ get dedupKey(): [string, string | null] {
35
+ return [this.constructor.name, this.entityId];
36
+ }
37
+
38
+ override toJSON(): NonVerbalReferenceJson | string {
39
+ if (this.display != null) {
40
+ return { ref: this.entityId ?? '', display: this.display };
41
+ }
42
+ return this.entityId ?? '';
43
+ }
44
+
45
+ static override fromJSON<T extends NonVerbalReference>(
46
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
47
+ this: new (...args: any[]) => T,
48
+ data: NonVerbalReferenceInput,
49
+ ): T | NonVerbalReference {
50
+ if (data instanceof NonVerbalReference) return data;
51
+ if (typeof data === 'string') {
52
+ return new (this as new (d: NonVerbalReferenceJson) => T)({ entityId: data });
53
+ }
54
+ const entityId =
55
+ data.entityId ?? data.entity_id ?? data.ref ?? data.id ?? null;
56
+ const display = data.display ?? null;
57
+ const type = data.type;
58
+ const Self = this as unknown as { _registry(): Map<string, AnyCtor> };
59
+ if (type) {
60
+ const Cls = Self._registry().get(type);
61
+ if (Cls) {
62
+ return new (Cls as new (d: NonVerbalReferenceJson) => T)({
63
+ entityId: entityId ?? undefined,
64
+ display: display ?? undefined,
65
+ });
66
+ }
67
+ }
68
+ return new (this as new (d: NonVerbalReferenceJson) => T)({
69
+ entityId: entityId ?? undefined,
70
+ display: display ?? undefined,
71
+ });
72
+ }
73
+ }
@@ -0,0 +1,29 @@
1
+ import { NonVerbalReference } from './non-verbal-reference.js';
2
+ import type { NonVerbalReferenceInput } from './non-verbal-reference.js';
3
+
4
+ export class FigureReference extends NonVerbalReference {
5
+ static override fromJSON(
6
+ data: NonVerbalReferenceInput,
7
+ ): FigureReference | NonVerbalReference {
8
+ return NonVerbalReference.fromJSON(data) as FigureReference | NonVerbalReference;
9
+ }
10
+ }
11
+ NonVerbalReference.register('figure', FigureReference);
12
+
13
+ export class TableReference extends NonVerbalReference {
14
+ static override fromJSON(
15
+ data: NonVerbalReferenceInput,
16
+ ): TableReference | NonVerbalReference {
17
+ return NonVerbalReference.fromJSON(data) as TableReference | NonVerbalReference;
18
+ }
19
+ }
20
+ NonVerbalReference.register('table', TableReference);
21
+
22
+ export class FormulaReference extends NonVerbalReference {
23
+ static override fromJSON(
24
+ data: NonVerbalReferenceInput,
25
+ ): FormulaReference | NonVerbalReference {
26
+ return NonVerbalReference.fromJSON(data) as FormulaReference | NonVerbalReference;
27
+ }
28
+ }
29
+ NonVerbalReference.register('formula', FormulaReference);