From 99f7c913e8eaeba6bfea70315e682a3964d3bff4 Mon Sep 17 00:00:00 2001 From: Ronald Tse Date: Mon, 22 Jun 2026 16:56:02 +0800 Subject: [PATCH] refactor(bridge): use native DetailedDefinition.examples (glossarist 0.4.2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #69 (b597b15) shipped scoped examples UI with a temporary WeakMap bridge because the published glossarist@0.4.0 DetailedDefinition class did not expose `examples` natively. That workaround was explicitly marked 'remove once the published model carries the field'. glossarist@0.4.2 (PR glossarist/glossarist-js#28, released today) adds `readonly examples: DetailedDefinition[]` to DetailedDefinition with the same lazy-instantiation pattern as `sources`. The bridge is now redundant — the model owns the nesting. Removed: - src/adapters/model-bridge.ts: extraNoteExamples WeakMap, getNoteExamples accessor, and the attachBridges block that paired raw with model instances for notes/definition/examples/annotations - src/composables/use-concept-content.ts: toRaw + getNoteExamples call, replaced with direct `n.examples` access Kept mapDetailedDefinitionFromJsonLd in model-bridge — it still translates JSON-LD wire shape (gl:content, gl:examples) to the DetailedDefinition.fromJSON input shape. Verified: full test suite (797 passing including the scoped-examples test from PR #69), vue-tsc clean, build clean. --- package-lock.json | 32 ++++++++++++++++++++++---- package.json | 2 +- src/adapters/model-bridge.ts | 26 --------------------- src/composables/use-concept-content.ts | 6 ++--- 4 files changed, 31 insertions(+), 35 deletions(-) diff --git a/package-lock.json b/package-lock.json index 291095a..e2e4e63 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "autoprefixer": "^10.4.21", "d3": "^7.9.0", "favicons": "^7.2.0", - "glossarist": "^0.4.0", + "glossarist": "^0.4.2", "js-yaml": "^4.1.0", "jszip": "^3.10.1", "pinia": "^2.3.1", @@ -8251,18 +8251,40 @@ } }, "node_modules/glossarist": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/glossarist/-/glossarist-0.4.0.tgz", - "integrity": "sha512-kc6cu8VZVPS2AV2in7NPKtfBDJMdLfpEMNkweQnvZ5pKOH23/U5VxYpgv/UaqqgDTlIxTbfobIUHqkxRM1snWQ==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/glossarist/-/glossarist-0.4.2.tgz", + "integrity": "sha512-pWckmvIFbWUp5MI0C2kbzin6YTteW6QM+3zx5n7n/Fj4SGPKmOCqgaI6gErh0/1IUBZ1LLHSxqglFLWG8A9xaQ==", "license": "MIT", "dependencies": { - "js-yaml": "^4.1.0", + "js-yaml": "^5.0.0", "jszip": "^3.10.1" }, "engines": { "node": ">=20" } }, + "node_modules/glossarist/node_modules/js-yaml": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.0.0.tgz", + "integrity": "sha512-GSvaPUbk1U+FMZ7rJzF+F8e5YVtu7KnD40et/5rBXXRBv2jCO9L3qCewvIDDdudC0QycTFlf6EAA+h3kxBsuUw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.mjs" + } + }, "node_modules/happy-dom": { "version": "20.10.2", "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-20.10.2.tgz", diff --git a/package.json b/package.json index 0aa983d..c69fc4b 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "autoprefixer": "^10.4.21", "d3": "^7.9.0", "favicons": "^7.2.0", - "glossarist": "^0.4.0", + "glossarist": "^0.4.2", "js-yaml": "^4.1.0", "jszip": "^3.10.1", "pinia": "^2.3.1", diff --git a/src/adapters/model-bridge.ts b/src/adapters/model-bridge.ts index 5acc594..cc4159d 100644 --- a/src/adapters/model-bridge.ts +++ b/src/adapters/model-bridge.ts @@ -184,13 +184,6 @@ export function getAnnotations(lc: LocalizedConcept): DetailedDefinition[] { return extraAnnotations.get(lc) ?? []; } -// Scoped examples: DetailedDefinition.examples (VIM 1993 nesting) -const extraNoteExamples = new WeakMap(); - -export function getNoteExamples(note: DetailedDefinition): DetailedDefinition[] { - return extraNoteExamples.get(note) ?? []; -} - // Designation relationship targets: RelatedConcept.target (string) const designationTargets = new WeakMap(); @@ -237,25 +230,6 @@ function attachBridges(concept: Concept, localizations: Record) )); } - // Scoped examples inside notes/definition/examples/annotations - for (const fieldName of ['notes', 'definition', 'examples', 'annotations'] as const) { - const rawList = rawObj[fieldName]; - const modelList = lc[fieldName] as DetailedDefinition[]; - if (!Array.isArray(rawList) || modelList.length === 0) continue; - for (let i = 0; i < Math.min(rawList.length, modelList.length); i++) { - const rawItem = rawList[i] as Record | undefined; - const rawExamples = rawItem?.examples; - if (!Array.isArray(rawExamples) || rawExamples.length === 0) continue; - const nested = rawExamples.map((e: Record) => - DetailedDefinition.fromJSON({ - content: (e.content as string) ?? '', - ...(Array.isArray(e.examples) ? { examples: e.examples } : {}), - }) as DetailedDefinition, - ); - extraNoteExamples.set(modelList[i], nested); - } - } - // Designation-level relationship targets, ref text, sourceId, citation const rawTerms = rawObj.terms; if (Array.isArray(rawTerms)) { diff --git a/src/composables/use-concept-content.ts b/src/composables/use-concept-content.ts index ddfa031..62e76bc 100644 --- a/src/composables/use-concept-content.ts +++ b/src/composables/use-concept-content.ts @@ -1,9 +1,9 @@ -import { computed, ref, watch, toRaw, type ComputedRef } from 'vue'; +import { computed, ref, watch, type ComputedRef } from 'vue'; import type { Concept, LocalizedConcept, ConceptSource, Designation, DetailedDefinition } from 'glossarist'; import type { Manifest } from '../adapters/types'; import type { RenderOptions } from '../utils/content-renderer'; import { renderContent, cleanContent } from '../utils/content-renderer'; -import { getAnnotations, getNoteExamples } from '../adapters/model-bridge'; +import { getAnnotations } from '../adapters/model-bridge'; import { getPreferredTerm, entryStatusColor, entryStatusLabel, entryStatusDefinition } from '../utils/concept-helpers'; import { sortLanguages } from '../utils/lang'; import { useSiteConfig } from '../config/use-site-config'; @@ -80,7 +80,7 @@ export function useConceptContent( .map(n => { const content = n.content ?? ''; if (!content) return null; - const nested = getNoteExamples(toRaw(n) as DetailedDefinition); + const nested = n.examples ?? []; const examples = nested .map(buildExample) .filter((e): e is ExampleEntry => e !== null);