docusaurus-plugin-glossary 3.1.0 → 3.2.0

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 (50) hide show
  1. package/dist/chunk-4CUFUKUA.js +109 -0
  2. package/dist/chunk-4CUFUKUA.js.map +1 -0
  3. package/dist/chunk-PEB4Y6RI.js +311 -0
  4. package/dist/chunk-PEB4Y6RI.js.map +1 -0
  5. package/dist/chunk-SNP37IVL.js +212 -0
  6. package/dist/chunk-SNP37IVL.js.map +1 -0
  7. package/dist/client/index.cjs +55 -0
  8. package/dist/client/index.cjs.map +1 -0
  9. package/dist/client/index.js +10 -21
  10. package/dist/client/index.js.map +1 -0
  11. package/dist/components/GlossaryPage.cjs +130 -0
  12. package/dist/components/GlossaryPage.cjs.map +1 -0
  13. package/dist/components/GlossaryPage.js +74 -113
  14. package/dist/components/GlossaryPage.js.map +1 -0
  15. package/dist/index.cjs +659 -0
  16. package/dist/index.cjs.map +1 -0
  17. package/dist/index.d.cts +173 -0
  18. package/dist/index.d.ts +82 -11
  19. package/dist/index.js +23 -173
  20. package/dist/index.js.map +1 -0
  21. package/dist/preset.cjs +710 -0
  22. package/dist/preset.cjs.map +1 -0
  23. package/dist/preset.d.cts +98 -0
  24. package/dist/preset.d.ts +8 -7
  25. package/dist/preset.js +79 -143
  26. package/dist/preset.js.map +1 -0
  27. package/dist/remark/glossary-terms.cjs +345 -0
  28. package/dist/remark/glossary-terms.cjs.map +1 -0
  29. package/dist/remark/glossary-terms.js +9 -440
  30. package/dist/remark/glossary-terms.js.map +1 -0
  31. package/dist/theme/GlossaryTerm/index.cjs +138 -0
  32. package/dist/theme/GlossaryTerm/index.cjs.map +1 -0
  33. package/dist/theme/GlossaryTerm/index.js +56 -90
  34. package/dist/theme/GlossaryTerm/index.js.map +1 -0
  35. package/dist/validation.cjs +238 -0
  36. package/dist/validation.cjs.map +1 -0
  37. package/dist/validation.d.cts +2 -0
  38. package/dist/validation.d.ts +2 -44
  39. package/dist/validation.js +11 -256
  40. package/dist/validation.js.map +1 -0
  41. package/package.json +25 -30
  42. package/dist/components/GlossaryPage.test.js +0 -205
  43. package/dist/index.d.ts.map +0 -1
  44. package/dist/preset.d.ts.map +0 -1
  45. package/dist/remark/glossary-terms.d.ts +0 -28
  46. package/dist/remark/glossary-terms.d.ts.map +0 -1
  47. package/dist/theme/GlossaryTerm/index.test.js +0 -143
  48. package/dist/validation.d.ts.map +0 -1
  49. /package/dist/{components/GlossaryPage.module.css → GlossaryPage.module-M4DEUP4X.module.css} +0 -0
  50. /package/dist/{theme/GlossaryTerm/styles.module.css → styles.module-N7ME3MWS.module.css} +0 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,659 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ GlossaryValidationError: () => GlossaryValidationError,
34
+ clearGlossaryCache: () => clearGlossaryCache,
35
+ default: () => glossaryPlugin,
36
+ formatValidationErrors: () => formatValidationErrors,
37
+ getRemarkPlugin: () => getRemarkPlugin,
38
+ remarkPlugin: () => remarkPlugin,
39
+ validateGlossaryData: () => validateGlossaryData
40
+ });
41
+ module.exports = __toCommonJS(src_exports);
42
+ var import_path2 = __toESM(require("path"), 1);
43
+ var import_url = require("url");
44
+ var import_fs_extra = __toESM(require("fs-extra"), 1);
45
+ var import_validate_peer_dependencies = __toESM(require("validate-peer-dependencies"), 1);
46
+
47
+ // src/remark/glossary-terms.js
48
+ var import_unist_util_visit = require("unist-util-visit");
49
+ var import_path = __toESM(require("path"), 1);
50
+ var import_fs = __toESM(require("fs"), 1);
51
+ function validateGlossaryTerms(data, _filePath) {
52
+ const errors = [];
53
+ const validTerms = [];
54
+ if (data === null || data === void 0) {
55
+ errors.push(`Glossary data is null or undefined`);
56
+ return { terms: [], errors };
57
+ }
58
+ if (typeof data !== "object") {
59
+ errors.push(`Glossary data must be an object, got ${typeof data}`);
60
+ return { terms: [], errors };
61
+ }
62
+ if (!("terms" in data)) {
63
+ errors.push(`Glossary data must contain a "terms" array`);
64
+ return { terms: [], errors };
65
+ }
66
+ if (!Array.isArray(data.terms)) {
67
+ errors.push(`Field "terms" must be an array, got ${typeof data.terms}`);
68
+ return { terms: [], errors };
69
+ }
70
+ data.terms.forEach((term, index) => {
71
+ if (term === null || term === void 0 || typeof term !== "object") {
72
+ errors.push(`terms[${index}]: Term must be an object`);
73
+ return;
74
+ }
75
+ if (typeof term.term !== "string" || term.term.trim() === "") {
76
+ errors.push(`terms[${index}]: Missing or invalid "term" field`);
77
+ return;
78
+ }
79
+ if (typeof term.definition !== "string") {
80
+ errors.push(`terms[${index}]: Missing or invalid "definition" field`);
81
+ return;
82
+ }
83
+ validTerms.push(term);
84
+ });
85
+ return { terms: validTerms, errors };
86
+ }
87
+ var glossaryCache = /* @__PURE__ */ new Map();
88
+ var CACHE_TTL = 5e3;
89
+ function remarkGlossaryTerms({
90
+ terms = [],
91
+ glossaryPath = null,
92
+ routePath = "/glossary",
93
+ siteDir = null
94
+ } = {}) {
95
+ let glossaryTerms = terms;
96
+ if (!glossaryTerms.length && glossaryPath && siteDir) {
97
+ try {
98
+ const glossaryFilePath = import_path.default.resolve(siteDir, glossaryPath);
99
+ const now = Date.now();
100
+ const cached = glossaryCache.get(glossaryFilePath);
101
+ if (cached && now - cached.loadedAt < CACHE_TTL) {
102
+ glossaryTerms = cached.terms;
103
+ } else {
104
+ if (import_fs.default.existsSync(glossaryFilePath)) {
105
+ const fileContent = import_fs.default.readFileSync(glossaryFilePath, "utf8");
106
+ let glossaryData;
107
+ try {
108
+ glossaryData = JSON.parse(fileContent);
109
+ } catch (parseError) {
110
+ console.error(
111
+ `[glossary-plugin] Failed to parse glossary JSON at ${glossaryPath}:`,
112
+ parseError.message
113
+ );
114
+ glossaryCache.set(glossaryFilePath, {
115
+ terms: [],
116
+ loadedAt: now
117
+ });
118
+ return (tree) => tree;
119
+ }
120
+ const { terms: validTerms, errors } = validateGlossaryTerms(glossaryData, glossaryPath);
121
+ if (errors.length > 0) {
122
+ console.warn(`[glossary-plugin] Glossary validation errors in ${glossaryPath}:`);
123
+ errors.forEach((err) => console.warn(` - ${err}`));
124
+ if (validTerms.length > 0) {
125
+ console.warn(`[glossary-plugin] Proceeding with ${validTerms.length} valid term(s).`);
126
+ }
127
+ }
128
+ glossaryTerms = validTerms;
129
+ glossaryCache.set(glossaryFilePath, {
130
+ terms: glossaryTerms,
131
+ loadedAt: now
132
+ });
133
+ if (!cached && process.env.NODE_ENV !== "production") {
134
+ console.log(
135
+ `[glossary-plugin] Loaded ${glossaryTerms.length} terms from ${glossaryPath}`
136
+ );
137
+ }
138
+ } else {
139
+ glossaryCache.set(glossaryFilePath, {
140
+ terms: [],
141
+ loadedAt: now
142
+ });
143
+ if (process.env.NODE_ENV !== "production") {
144
+ console.warn(`[glossary-plugin] Glossary file not found: ${glossaryPath}`);
145
+ }
146
+ }
147
+ }
148
+ } catch (error) {
149
+ console.warn(
150
+ `[glossary-plugin] Failed to load glossary from ${glossaryPath}:`,
151
+ error.message
152
+ );
153
+ if (glossaryPath && siteDir) {
154
+ const glossaryFilePath = import_path.default.resolve(siteDir, glossaryPath);
155
+ glossaryCache.set(glossaryFilePath, {
156
+ terms: [],
157
+ loadedAt: Date.now()
158
+ });
159
+ }
160
+ }
161
+ }
162
+ const termMap = /* @__PURE__ */ new Map();
163
+ glossaryTerms.forEach((termObj) => {
164
+ if (termObj.term && termObj.autoLink !== false) {
165
+ termMap.set(termObj.term.toLowerCase(), termObj);
166
+ }
167
+ });
168
+ const sortedTerms = Array.from(termMap.entries()).sort((a, b) => b[0].length - a[0].length);
169
+ if (sortedTerms.length === 0) {
170
+ return (tree) => tree;
171
+ }
172
+ function replaceTermsInText(text) {
173
+ if (!text || !sortedTerms.length) {
174
+ return [{ type: "text", value: text }];
175
+ }
176
+ const result = [];
177
+ let lastIndex = 0;
178
+ const textLower = text.toLowerCase();
179
+ const matches = [];
180
+ for (const [lowerTerm, termObj] of sortedTerms) {
181
+ const term = termObj.term;
182
+ let searchIndex = 0;
183
+ while (searchIndex < textLower.length) {
184
+ const index = textLower.indexOf(lowerTerm, searchIndex);
185
+ if (index === -1) break;
186
+ const beforeChar = index > 0 ? textLower[index - 1] : " ";
187
+ const afterIndex = index + lowerTerm.length;
188
+ const afterChar = afterIndex < textLower.length ? textLower[afterIndex] : " ";
189
+ let matchLength = term.length;
190
+ let isWordBoundary = !/\w/.test(beforeChar) && !/\w/.test(afterChar);
191
+ if (!isWordBoundary && afterChar === "s") {
192
+ const nextChar = afterIndex + 1 < textLower.length ? textLower[afterIndex + 1] : " ";
193
+ if (!/\w/.test(nextChar)) {
194
+ isWordBoundary = true;
195
+ matchLength = term.length + 1;
196
+ }
197
+ }
198
+ if (!isWordBoundary && afterChar === "e" && afterIndex + 1 < textLower.length && textLower[afterIndex + 1] === "s") {
199
+ const nextChar = afterIndex + 2 < textLower.length ? textLower[afterIndex + 2] : " ";
200
+ if (!/\w/.test(nextChar)) {
201
+ isWordBoundary = true;
202
+ matchLength = term.length + 2;
203
+ }
204
+ }
205
+ if (isWordBoundary) {
206
+ matches.push({
207
+ index,
208
+ length: matchLength,
209
+ term,
210
+ termObj,
211
+ // Store original case from the text
212
+ originalText: text.substring(index, index + matchLength)
213
+ });
214
+ }
215
+ searchIndex = index + 1;
216
+ }
217
+ }
218
+ matches.sort((a, b) => a.index - b.index);
219
+ const nonOverlappingMatches = [];
220
+ let lastMatchEnd = 0;
221
+ for (const match of matches) {
222
+ if (match.index >= lastMatchEnd) {
223
+ nonOverlappingMatches.push(match);
224
+ lastMatchEnd = match.index + match.length;
225
+ }
226
+ }
227
+ for (const match of nonOverlappingMatches) {
228
+ if (match.index > lastIndex) {
229
+ result.push({
230
+ type: "text",
231
+ value: text.substring(lastIndex, match.index)
232
+ });
233
+ }
234
+ result.push({
235
+ type: "mdxJsxFlowElement",
236
+ name: "GlossaryTerm",
237
+ attributes: [
238
+ {
239
+ type: "mdxJsxAttribute",
240
+ name: "term",
241
+ value: match.termObj.term
242
+ },
243
+ {
244
+ type: "mdxJsxAttribute",
245
+ name: "definition",
246
+ value: match.termObj.definition || ""
247
+ },
248
+ {
249
+ type: "mdxJsxAttribute",
250
+ name: "routePath",
251
+ value: routePath
252
+ }
253
+ ],
254
+ children: [
255
+ {
256
+ type: "text",
257
+ value: match.originalText
258
+ }
259
+ ]
260
+ });
261
+ lastIndex = match.index + match.length;
262
+ }
263
+ if (lastIndex < text.length) {
264
+ result.push({
265
+ type: "text",
266
+ value: text.substring(lastIndex)
267
+ });
268
+ }
269
+ return result.length > 0 ? result : [{ type: "text", value: text }];
270
+ }
271
+ const transformer = (tree) => {
272
+ let usedGlossaryTerm = false;
273
+ (0, import_unist_util_visit.visit)(tree, "text", (node, index, parent) => {
274
+ if (parent.type === "code" || parent.type === "inlineCode" || parent.type === "link" || parent.type === "mdxJsxFlowElement" || parent.type === "mdxJsxTextElement") {
275
+ return;
276
+ }
277
+ const replacements = replaceTermsInText(node.value);
278
+ if (replacements.length > 1 || replacements.length === 1 && replacements[0].type !== "text") {
279
+ const newNodes = replacements.map((replacement) => {
280
+ if (replacement.type === "mdxJsxFlowElement") {
281
+ if (parent.type === "paragraph") {
282
+ usedGlossaryTerm = true;
283
+ return {
284
+ type: "mdxJsxTextElement",
285
+ name: replacement.name,
286
+ attributes: replacement.attributes,
287
+ children: replacement.children
288
+ };
289
+ }
290
+ usedGlossaryTerm = true;
291
+ }
292
+ return replacement;
293
+ });
294
+ parent.children.splice(index, 1, ...newNodes);
295
+ return index + newNodes.length - 1;
296
+ }
297
+ });
298
+ if (usedGlossaryTerm) {
299
+ const importNode = {
300
+ type: "mdxjsEsm",
301
+ value: 'import GlossaryTerm from "@theme/GlossaryTerm";',
302
+ data: {
303
+ estree: {
304
+ type: "Program",
305
+ sourceType: "module",
306
+ body: [
307
+ {
308
+ type: "ImportDeclaration",
309
+ specifiers: [
310
+ {
311
+ type: "ImportDefaultSpecifier",
312
+ local: { type: "Identifier", name: "GlossaryTerm" }
313
+ }
314
+ ],
315
+ source: {
316
+ type: "Literal",
317
+ value: "@theme/GlossaryTerm",
318
+ raw: '"@theme/GlossaryTerm"'
319
+ }
320
+ }
321
+ ]
322
+ }
323
+ }
324
+ };
325
+ const hasImport = Array.isArray(tree.children) && tree.children.some(
326
+ (n) => n.type === "mdxjsEsm" && (n.value?.includes("@theme/GlossaryTerm") || n.data?.estree?.body?.some((s) => s.source?.value === "@theme/GlossaryTerm"))
327
+ );
328
+ if (!hasImport) {
329
+ if (!Array.isArray(tree.children)) tree.children = [];
330
+ let insertIndex = 0;
331
+ for (let i = 0; i < tree.children.length; i++) {
332
+ const node = tree.children[i];
333
+ if (node.type === "yaml" || node.type === "toml") {
334
+ insertIndex = i + 1;
335
+ } else {
336
+ break;
337
+ }
338
+ }
339
+ tree.children.splice(insertIndex, 0, importNode);
340
+ }
341
+ }
342
+ };
343
+ return transformer;
344
+ }
345
+ function clearGlossaryCache(filePath) {
346
+ if (filePath) {
347
+ glossaryCache.delete(filePath);
348
+ } else {
349
+ glossaryCache.clear();
350
+ }
351
+ }
352
+
353
+ // src/validation.ts
354
+ function validateTerm(term, index) {
355
+ const errors = [];
356
+ const prefix = `terms[${index}]`;
357
+ if (term === null || term === void 0) {
358
+ errors.push({
359
+ field: prefix,
360
+ message: "Term cannot be null or undefined",
361
+ value: term
362
+ });
363
+ return errors;
364
+ }
365
+ if (typeof term !== "object") {
366
+ errors.push({
367
+ field: prefix,
368
+ message: `Term must be an object, got ${typeof term}`,
369
+ value: term
370
+ });
371
+ return errors;
372
+ }
373
+ const termObj = term;
374
+ if (!("term" in termObj)) {
375
+ errors.push({
376
+ field: `${prefix}.term`,
377
+ message: 'Missing required field "term"'
378
+ });
379
+ } else if (typeof termObj.term !== "string") {
380
+ errors.push({
381
+ field: `${prefix}.term`,
382
+ message: `Field "term" must be a string, got ${typeof termObj.term}`,
383
+ value: termObj.term
384
+ });
385
+ } else if (termObj.term.trim() === "") {
386
+ errors.push({
387
+ field: `${prefix}.term`,
388
+ message: 'Field "term" cannot be empty',
389
+ value: termObj.term
390
+ });
391
+ }
392
+ if (!("definition" in termObj)) {
393
+ errors.push({
394
+ field: `${prefix}.definition`,
395
+ message: 'Missing required field "definition"'
396
+ });
397
+ } else if (typeof termObj.definition !== "string") {
398
+ errors.push({
399
+ field: `${prefix}.definition`,
400
+ message: `Field "definition" must be a string, got ${typeof termObj.definition}`,
401
+ value: termObj.definition
402
+ });
403
+ }
404
+ if ("abbreviation" in termObj && termObj.abbreviation !== void 0) {
405
+ if (typeof termObj.abbreviation !== "string") {
406
+ errors.push({
407
+ field: `${prefix}.abbreviation`,
408
+ message: `Field "abbreviation" must be a string, got ${typeof termObj.abbreviation}`,
409
+ value: termObj.abbreviation
410
+ });
411
+ }
412
+ }
413
+ if ("relatedTerms" in termObj && termObj.relatedTerms !== void 0) {
414
+ if (!Array.isArray(termObj.relatedTerms)) {
415
+ errors.push({
416
+ field: `${prefix}.relatedTerms`,
417
+ message: `Field "relatedTerms" must be an array, got ${typeof termObj.relatedTerms}`,
418
+ value: termObj.relatedTerms
419
+ });
420
+ } else {
421
+ termObj.relatedTerms.forEach((relatedTerm, relatedIndex) => {
422
+ if (typeof relatedTerm !== "string") {
423
+ errors.push({
424
+ field: `${prefix}.relatedTerms[${relatedIndex}]`,
425
+ message: `Related term must be a string, got ${typeof relatedTerm}`,
426
+ value: relatedTerm
427
+ });
428
+ }
429
+ });
430
+ }
431
+ }
432
+ if ("id" in termObj && termObj.id !== void 0) {
433
+ if (typeof termObj.id !== "string") {
434
+ errors.push({
435
+ field: `${prefix}.id`,
436
+ message: `Field "id" must be a string, got ${typeof termObj.id}`,
437
+ value: termObj.id
438
+ });
439
+ }
440
+ }
441
+ if ("autoLink" in termObj && termObj.autoLink !== void 0) {
442
+ if (typeof termObj.autoLink !== "boolean") {
443
+ errors.push({
444
+ field: `${prefix}.autoLink`,
445
+ message: `Field "autoLink" must be a boolean, got ${typeof termObj.autoLink}`,
446
+ value: termObj.autoLink
447
+ });
448
+ }
449
+ }
450
+ return errors;
451
+ }
452
+ function validateGlossaryData(data, options = {}) {
453
+ const { throwOnError = true } = options;
454
+ const errors = [];
455
+ if (data === null || data === void 0) {
456
+ errors.push({
457
+ field: "root",
458
+ message: "Glossary data cannot be null or undefined",
459
+ value: data
460
+ });
461
+ if (throwOnError && errors.length > 0) {
462
+ throw new GlossaryValidationError(errors);
463
+ }
464
+ return { valid: false, errors, data: { terms: [] } };
465
+ }
466
+ if (typeof data !== "object") {
467
+ errors.push({
468
+ field: "root",
469
+ message: `Glossary data must be an object, got ${typeof data}`,
470
+ value: data
471
+ });
472
+ if (throwOnError && errors.length > 0) {
473
+ throw new GlossaryValidationError(errors);
474
+ }
475
+ return { valid: false, errors, data: { terms: [] } };
476
+ }
477
+ const glossaryData = data;
478
+ if (!("terms" in glossaryData)) {
479
+ errors.push({
480
+ field: "terms",
481
+ message: 'Glossary data must contain a "terms" array'
482
+ });
483
+ if (throwOnError && errors.length > 0) {
484
+ throw new GlossaryValidationError(errors);
485
+ }
486
+ return { valid: false, errors, data: { terms: [] } };
487
+ }
488
+ if (!Array.isArray(glossaryData.terms)) {
489
+ errors.push({
490
+ field: "terms",
491
+ message: `Field "terms" must be an array, got ${typeof glossaryData.terms}`,
492
+ value: glossaryData.terms
493
+ });
494
+ if (throwOnError && errors.length > 0) {
495
+ throw new GlossaryValidationError(errors);
496
+ }
497
+ return { valid: false, errors, data: { terms: [] } };
498
+ }
499
+ const validTerms = [];
500
+ glossaryData.terms.forEach((term, index) => {
501
+ const termErrors = validateTerm(term, index);
502
+ if (termErrors.length > 0) {
503
+ errors.push(...termErrors);
504
+ } else {
505
+ validTerms.push(term);
506
+ }
507
+ });
508
+ const termNames = /* @__PURE__ */ new Map();
509
+ validTerms.forEach((term, index) => {
510
+ const lowerName = term.term.toLowerCase();
511
+ if (termNames.has(lowerName)) {
512
+ errors.push({
513
+ field: `terms[${index}].term`,
514
+ message: `Duplicate term "${term.term}" (first occurrence at index ${termNames.get(lowerName)})`,
515
+ value: term.term
516
+ });
517
+ } else {
518
+ termNames.set(lowerName, index);
519
+ }
520
+ });
521
+ if (throwOnError && errors.length > 0) {
522
+ throw new GlossaryValidationError(errors);
523
+ }
524
+ return {
525
+ valid: errors.length === 0,
526
+ errors,
527
+ data: { terms: validTerms }
528
+ };
529
+ }
530
+ var GlossaryValidationError = class _GlossaryValidationError extends Error {
531
+ constructor(errors) {
532
+ const message = formatValidationErrors(errors);
533
+ super(message);
534
+ this.name = "GlossaryValidationError";
535
+ this.errors = errors;
536
+ if (Error.captureStackTrace) {
537
+ Error.captureStackTrace(this, _GlossaryValidationError);
538
+ }
539
+ }
540
+ };
541
+ function formatValidationErrors(errors) {
542
+ if (errors.length === 0) {
543
+ return "No validation errors";
544
+ }
545
+ const header = `Glossary validation failed with ${errors.length} error${errors.length > 1 ? "s" : ""}:`;
546
+ const errorList = errors.map((err, index) => {
547
+ let msg = ` ${index + 1}. [${err.field}] ${err.message}`;
548
+ if (err.value !== void 0) {
549
+ const valueStr = typeof err.value === "object" ? JSON.stringify(err.value) : String(err.value);
550
+ const truncated = valueStr.length > 50 ? valueStr.substring(0, 50) + "..." : valueStr;
551
+ msg += ` (got: ${truncated})`;
552
+ }
553
+ return msg;
554
+ }).join("\n");
555
+ return `${header}
556
+ ${errorList}`;
557
+ }
558
+
559
+ // src/index.ts
560
+ var import_meta = {};
561
+ var currentFilePath = (0, import_url.fileURLToPath)(import_meta.url);
562
+ var currentDir = import_path2.default.dirname(currentFilePath);
563
+ (0, import_validate_peer_dependencies.default)(currentDir);
564
+ function glossaryPlugin(context, options = {}) {
565
+ const { glossaryPath = "glossary/glossary.json", routePath = "/glossary" } = options;
566
+ return {
567
+ name: "docusaurus-plugin-glossary",
568
+ getClientModules() {
569
+ return [import_path2.default.resolve(currentDir, "./client/index.js")];
570
+ },
571
+ async loadContent() {
572
+ const glossaryFilePath = import_path2.default.resolve(context.siteDir, glossaryPath);
573
+ if (await import_fs_extra.default.pathExists(glossaryFilePath)) {
574
+ try {
575
+ const rawData = await import_fs_extra.default.readJson(glossaryFilePath);
576
+ const validationResult = validateGlossaryData(rawData, { throwOnError: false });
577
+ if (!validationResult.valid) {
578
+ console.warn(
579
+ `[glossary-plugin] Glossary file has validation errors at ${glossaryFilePath}:`
580
+ );
581
+ validationResult.errors.forEach((err) => {
582
+ console.warn(` - [${err.field}] ${err.message}`);
583
+ });
584
+ console.warn("[glossary-plugin] Proceeding with valid terms only.");
585
+ }
586
+ return validationResult.data;
587
+ } catch (error) {
588
+ if (error instanceof GlossaryValidationError) {
589
+ throw error;
590
+ }
591
+ throw new Error(
592
+ `Failed to parse glossary file at ${glossaryFilePath}: ${error instanceof Error ? error.message : String(error)}`
593
+ );
594
+ }
595
+ }
596
+ console.warn(`Glossary file not found at ${glossaryFilePath}. Using empty glossary.`);
597
+ return { terms: [] };
598
+ },
599
+ async contentLoaded({ content, actions }) {
600
+ const { createData, addRoute, setGlobalData } = actions;
601
+ const glossaryContent = content;
602
+ const glossaryDataPath = await createData(
603
+ "glossary-data.json",
604
+ JSON.stringify(glossaryContent)
605
+ );
606
+ await createData(
607
+ "remark-glossary-data.json",
608
+ JSON.stringify({
609
+ terms: glossaryContent.terms || [],
610
+ routePath
611
+ })
612
+ );
613
+ addRoute({
614
+ path: routePath,
615
+ component: import_path2.default.join(currentDir, "components/GlossaryPage.js"),
616
+ exact: true,
617
+ modules: {
618
+ glossaryData: glossaryDataPath
619
+ }
620
+ });
621
+ setGlobalData({
622
+ terms: glossaryContent.terms || [],
623
+ routePath
624
+ });
625
+ },
626
+ getThemePath() {
627
+ return import_path2.default.resolve(currentDir, "./theme");
628
+ },
629
+ getPathsToWatch() {
630
+ return [import_path2.default.resolve(context.siteDir, glossaryPath)];
631
+ },
632
+ async postBuild() {
633
+ console.log("Glossary plugin: Build completed");
634
+ }
635
+ };
636
+ }
637
+ var remarkPlugin = remarkGlossaryTerms;
638
+ function getRemarkPlugin(pluginOptions, context) {
639
+ const { glossaryPath = "glossary/glossary.json", routePath = "/glossary" } = pluginOptions;
640
+ const siteDir = context?.siteDir;
641
+ return [
642
+ remarkGlossaryTerms,
643
+ {
644
+ glossaryPath,
645
+ routePath,
646
+ siteDir
647
+ }
648
+ ];
649
+ }
650
+ // Annotate the CommonJS export names for ESM import in node:
651
+ 0 && (module.exports = {
652
+ GlossaryValidationError,
653
+ clearGlossaryCache,
654
+ formatValidationErrors,
655
+ getRemarkPlugin,
656
+ remarkPlugin,
657
+ validateGlossaryData
658
+ });
659
+ //# sourceMappingURL=index.cjs.map