docusaurus-plugin-glossary 1.1.2 → 1.3.1

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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  A comprehensive Docusaurus plugin that provides glossary functionality with an auto-generated glossary page, searchable terms, and inline term tooltips.
4
4
 
5
- > Compatibility: Fully compatible with Docusaurus v3 (MDX v3). If you were on a v2-era fork, please upgrade to the latest 1.x release of this plugin. No manual MDX pipeline wiring is required when `autoLinkTerms` is enabled (default).
5
+ > Compatibility: Fully compatible with Docusaurus v3 (MDX v3). If you were on a v2-era fork, please upgrade to the latest 1.x release of this plugin.
6
6
 
7
7
  ## Features
8
8
 
@@ -18,31 +18,66 @@ A comprehensive Docusaurus plugin that provides glossary functionality with an a
18
18
  ## Quick Start
19
19
 
20
20
  1. **Install the plugin:**
21
+
21
22
  ```bash
22
23
  npm install docusaurus-plugin-glossary
23
24
  ```
24
25
 
25
26
  2. **Add to your `docusaurus.config.js`:**
27
+
26
28
  ```javascript
29
+ const glossaryPlugin = require('docusaurus-plugin-glossary');
30
+
27
31
  module.exports = {
28
32
  // ... other config
33
+ presets: [
34
+ [
35
+ '@docusaurus/preset-classic',
36
+ {
37
+ docs: {
38
+ // Add the remark plugin to enable auto-linking in docs
39
+ remarkPlugins: [
40
+ glossaryPlugin.getRemarkPlugin(
41
+ {
42
+ glossaryPath: 'glossary/glossary.json',
43
+ routePath: '/glossary',
44
+ },
45
+ { siteDir: __dirname }
46
+ ),
47
+ ],
48
+ },
49
+ pages: {
50
+ // Add the remark plugin to enable auto-linking in pages
51
+ remarkPlugins: [
52
+ glossaryPlugin.getRemarkPlugin(
53
+ {
54
+ glossaryPath: 'glossary/glossary.json',
55
+ routePath: '/glossary',
56
+ },
57
+ { siteDir: __dirname }
58
+ ),
59
+ ],
60
+ },
61
+ },
62
+ ],
63
+ ],
29
64
  plugins: [
30
65
  [
31
66
  'docusaurus-plugin-glossary',
32
67
  {
33
68
  glossaryPath: 'glossary/glossary.json', // Path to your glossary file
34
69
  routePath: '/glossary', // URL path for glossary page
35
- autoLinkTerms: true, // Automatically link terms (default: true)
36
70
  },
37
71
  ],
38
72
  ],
39
73
  // ... other config
40
74
  };
41
75
  ```
42
-
43
- **That’s it!** On Docusaurus v3, the remark plugin is automatically configured via the plugin’s `configureMarkdown` hook no manual `markdown.remarkPlugins` setup needed.
76
+
77
+ **Note:** You need to configure the remark plugin in both the plugin AND the preset (for docs/pages) to enable auto-linking of terms.
44
78
 
45
79
  3. **Create your glossary file at `glossary/glossary.json`:**
80
+
46
81
  ```json
47
82
  {
48
83
  "description": "A collection of technical terms and their definitions",
@@ -64,11 +99,12 @@ A comprehensive Docusaurus plugin that provides glossary functionality with an a
64
99
  ```
65
100
 
66
101
  4. **Start your dev server:**
102
+
67
103
  ```bash
68
104
  npm run start
69
105
  ```
70
106
 
71
- 5. **That's it!**
107
+ 5. **That's it!**
72
108
  - Visit `/glossary` to see your glossary page
73
109
  - Write markdown normally - terms will automatically be linked with tooltips
74
110
  - Use `<GlossaryTerm>` component in MDX for manual control
@@ -108,10 +144,12 @@ Create a JSON file at `glossary/glossary.json` (or your configured path) in your
108
144
  ```
109
145
 
110
146
  **Required fields:**
147
+
111
148
  - `term` (string): The glossary term name
112
149
  - `definition` (string): The term's definition
113
150
 
114
151
  **Optional fields:**
152
+
115
153
  - `abbreviation` (string): The full form if the term is an abbreviation
116
154
  - `relatedTerms` (string[]): Array of related term names that link to other glossary entries
117
155
  - `id` (string): Custom ID for linking (auto-generated from term name if not provided)
@@ -121,72 +159,111 @@ Create a JSON file at `glossary/glossary.json` (or your configured path) in your
121
159
  Add the plugin to your `docusaurus.config.js`:
122
160
 
123
161
  ```javascript
162
+ const glossaryPlugin = require('docusaurus-plugin-glossary');
163
+
124
164
  module.exports = {
165
+ presets: [
166
+ [
167
+ '@docusaurus/preset-classic',
168
+ {
169
+ docs: {
170
+ // Add the remark plugin to enable auto-linking in docs
171
+ remarkPlugins: [
172
+ glossaryPlugin.getRemarkPlugin(
173
+ {
174
+ glossaryPath: 'glossary/glossary.json',
175
+ routePath: '/glossary',
176
+ },
177
+ { siteDir: __dirname }
178
+ ),
179
+ ],
180
+ },
181
+ pages: {
182
+ // Add the remark plugin to enable auto-linking in pages
183
+ remarkPlugins: [
184
+ glossaryPlugin.getRemarkPlugin(
185
+ {
186
+ glossaryPath: 'glossary/glossary.json',
187
+ routePath: '/glossary',
188
+ },
189
+ { siteDir: __dirname }
190
+ ),
191
+ ],
192
+ },
193
+ },
194
+ ],
195
+ ],
125
196
  plugins: [
126
197
  [
127
198
  'docusaurus-plugin-glossary',
128
199
  {
129
200
  glossaryPath: 'glossary/glossary.json', // Path to your glossary file
130
201
  routePath: '/glossary', // URL path for the glossary page
131
- autoLinkTerms: true, // Automatically detect and link terms (default: true)
132
202
  },
133
203
  ],
134
204
  ],
135
205
  };
136
206
  ```
137
207
 
138
- **Automatic Configuration:** The remark plugin is automatically configured when `autoLinkTerms` is `true` (the default). You don't need to manually configure `markdown.remarkPlugins`!
208
+ **Required Configuration:** To enable automatic term detection and linking, you must configure the remark plugin in your preset (as shown above). The plugin provides a `getRemarkPlugin` helper to make this easier.
139
209
 
140
- **Advanced: Manual Remark Plugin Configuration**
210
+ **Alternative: Using remarkPlugin directly**
141
211
 
142
- If you need more control or want to disable automatic detection, you can manually configure the remark plugin:
212
+ You can also use the `remarkPlugin` export directly if you prefer:
143
213
 
144
214
  ```javascript
145
215
  const glossaryPlugin = require('docusaurus-plugin-glossary');
146
216
 
147
217
  module.exports = {
218
+ presets: [
219
+ [
220
+ '@docusaurus/preset-classic',
221
+ {
222
+ docs: {
223
+ remarkPlugins: [
224
+ [
225
+ glossaryPlugin.remarkPlugin,
226
+ {
227
+ glossaryPath: 'glossary/glossary.json',
228
+ routePath: '/glossary',
229
+ siteDir: __dirname,
230
+ },
231
+ ],
232
+ ],
233
+ },
234
+ },
235
+ ],
236
+ ],
148
237
  plugins: [
149
238
  [
150
239
  'docusaurus-plugin-glossary',
151
240
  {
152
241
  glossaryPath: 'glossary/glossary.json',
153
242
  routePath: '/glossary',
154
- autoLinkTerms: false, // Disable automatic configuration
155
243
  },
156
244
  ],
157
245
  ],
158
- markdown: {
159
- remarkPlugins: [
160
- [
161
- glossaryPlugin.remarkPlugin,
162
- {
163
- glossaryPath: 'glossary/glossary.json',
164
- routePath: '/glossary',
165
- siteDir: process.cwd(),
166
- },
167
- ],
168
- ],
169
- },
170
246
  };
171
247
  ```
172
248
 
173
249
  ## Docusaurus v3 Notes and Troubleshooting
174
250
 
175
251
  - **MDX imports**: The plugin injects `import GlossaryTerm from '@theme/GlossaryTerm';` automatically when it auto-links a term. If you’re writing MDX manually, you can also import and use it yourself:
176
-
252
+
177
253
  ```mdx
178
254
  import GlossaryTerm from '@theme/GlossaryTerm';
179
-
255
+
180
256
  Our <GlossaryTerm term="API" /> uses <GlossaryTerm term="REST">RESTful</GlossaryTerm> principles.
181
257
  ```
182
258
 
183
259
  - **No tooltips or no auto-linking?**
184
- - Confirm youre on `@docusaurus/core@^3` and `react@^18`.
185
- - Ensure the plugin is listed in `plugins` and `autoLinkTerms` is not disabled.
260
+ - Confirm you're on `@docusaurus/core@^3` and `react@^18`.
261
+ - Ensure the plugin is listed in `plugins` AND the remark plugin is configured in your preset (see Step 2 above).
186
262
  - Visit `/glossary`. If the page or route fails to render, verify your `glossaryPath` file exists and contains a `terms` array.
263
+ - Clear your Docusaurus cache with `npm run clear` and restart your dev server.
187
264
  - If you previously used a local patch for `1.0.0`, remove it when using `1.0.2+`; the plugin bundles the v3-compatible theme and remark integration.
188
265
 
189
- - **Opting out of auto-linking**: set `autoLinkTerms: false` and add the remark plugin manually (see above), or only use the `<GlossaryTerm />` component where you want explicit control.
266
+ - **Opting out of auto-linking**: Simply don't configure the remark plugin in your preset. You can still use the `<GlossaryTerm />` component manually where you want explicit control.
190
267
 
191
268
  ### Step 3: Use Glossary Terms in Your Content
192
269
 
@@ -201,12 +278,14 @@ This project supports webhooks for real-time notifications.
201
278
  ```
202
279
 
203
280
  Terms like "API", "REST", and "webhooks" will automatically be:
281
+
204
282
  - Detected if they're defined in your glossary
205
283
  - Styled with a dotted underline
206
284
  - Display a tooltip with the definition on hover
207
285
  - Link to the full glossary page entry
208
286
 
209
287
  **Limitations:**
288
+
210
289
  - Only whole words are matched (respects word boundaries)
211
290
  - Terms inside code blocks, links, or existing MDX components are **not** processed
212
291
  - Matching is case-insensitive
@@ -228,6 +307,7 @@ Our <GlossaryTerm term="API" definition="Application Programming Interface">REST
228
307
  ```
229
308
 
230
309
  **Component props:**
310
+
231
311
  - `term` (required): The term name (used to look up definition from glossary)
232
312
  - `definition` (optional): Override the definition from the glossary file
233
313
  - `children` (optional): Custom text to display (defaults to term name)
@@ -237,6 +317,7 @@ Our <GlossaryTerm term="API" definition="Application Programming Interface">REST
237
317
  The glossary page is automatically available at `/glossary` (or your configured `routePath`).
238
318
 
239
319
  **Features:**
320
+
240
321
  - Alphabetical grouping with letter navigation
241
322
  - Real-time search across terms and definitions
242
323
  - Clickable related terms
@@ -252,7 +333,7 @@ module.exports = {
252
333
  themeConfig: {
253
334
  navbar: {
254
335
  items: [
255
- {to: '/glossary', label: 'Glossary', position: 'left'},
336
+ { to: '/glossary', label: 'Glossary', position: 'left' },
256
337
  // ... other items
257
338
  ],
258
339
  },
@@ -262,11 +343,10 @@ module.exports = {
262
343
 
263
344
  ## Configuration Options
264
345
 
265
- | Option | Type | Default | Description |
266
- | -------------- | ------- | -------------------------- | ----------------------------------------------------- |
267
- | `glossaryPath` | string | `'glossary/glossary.json'` | Path to glossary JSON file relative to site directory |
268
- | `routePath` | string | `'/glossary'` | URL path for glossary page |
269
- | `autoLinkTerms`| boolean | `true` | Enable automatic term detection in markdown (requires remark plugin configuration) |
346
+ | Option | Type | Default | Description |
347
+ | -------------- | ------ | -------------------------- | ----------------------------------------------------- |
348
+ | `glossaryPath` | string | `'glossary/glossary.json'` | Path to glossary JSON file relative to site directory |
349
+ | `routePath` | string | `'/glossary'` | URL path for glossary page |
270
350
 
271
351
  ## Customization
272
352
 
@@ -429,12 +509,12 @@ The remark plugin (`remark/glossary-terms.js`) automatically detects glossary te
429
509
 
430
510
  ### Automatic term detection not working
431
511
 
432
- - Ensure `autoLinkTerms` is `true` (the default) in your plugin configuration
433
- - The remark plugin is automatically configured, so you don't need to manually add it to `markdown.remarkPlugins`
512
+ - **IMPORTANT**: Ensure you have configured the remark plugin in your preset (see Configuration section above)
434
513
  - Verify your glossary file exists at the configured `glossaryPath` and contains terms
435
514
  - Check that terms in your content match the terms in your glossary (matching is case-insensitive but respects word boundaries)
436
515
  - Try clearing cache with `npm run clear` and restarting the dev server
437
516
  - Note that terms inside code blocks, links, or MDX components are not processed
517
+ - Make sure you've added the remark plugin to both `docs` and `pages` sections if you want auto-linking in both
438
518
  - If you've manually configured the remark plugin, ensure `siteDir` points to the correct Docusaurus site directory
439
519
 
440
520
  ### Styles not applying
@@ -449,7 +529,7 @@ MIT
449
529
 
450
530
  ## Contributing
451
531
 
452
- Contributions are welcome! Please open an issue or submit a pull request.
532
+ Contributions are welcome! Please see our [Contributing Guide](CONTRIBUTING.md) for details on how to get started.
453
533
 
454
534
  ## Credits
455
535
 
package/lib/index.js ADDED
@@ -0,0 +1,246 @@
1
+ var _a, _b;
2
+ import path from 'path';
3
+ import fs from 'fs-extra';
4
+ import { createRequire } from 'module';
5
+ import validatePeerDependencies from 'validate-peer-dependencies';
6
+ import remarkGlossaryTerms from './remark/glossary-terms.js';
7
+ // Helper function to compute __dirname lazily when needed
8
+ // This avoids webpack bundling issues by not using fileURLToPath at module load time
9
+ function getDirname() {
10
+ var _a;
11
+ // Check if we're in a Node.js environment
12
+ if (typeof process === 'undefined' || !((_a = process.versions) === null || _a === void 0 ? void 0 : _a.node)) {
13
+ return '';
14
+ }
15
+ // Use cached value if available
16
+ if (globalThis.__dirnameCache) {
17
+ return globalThis.__dirnameCache;
18
+ }
19
+ // In Jest/Babel transformed environment, __filename is available
20
+ // @ts-ignore - __filename is available after Babel transforms ES modules to CommonJS
21
+ if (typeof __filename !== 'undefined') {
22
+ const computedDirname = path.dirname(__filename);
23
+ globalThis.__dirnameCache = computedDirname;
24
+ return computedDirname;
25
+ }
26
+ // Check if import.meta.url is available
27
+ // Use try-catch to handle cases where import.meta is undefined (e.g., in Jest before transform)
28
+ let hasImportMetaUrl = false;
29
+ try {
30
+ hasImportMetaUrl = typeof import.meta.url !== 'undefined';
31
+ }
32
+ catch {
33
+ // import.meta is undefined (e.g., in Jest environment before Babel transform)
34
+ return '';
35
+ }
36
+ if (!hasImportMetaUrl) {
37
+ return '';
38
+ }
39
+ // Try to compute __dirname using fileURLToPath via createRequire
40
+ // This avoids webpack trying to bundle fileURLToPath at module load time
41
+ try {
42
+ const require = createRequire(import.meta.url);
43
+ const urlModule = require('url');
44
+ // Check if fileURLToPath is actually a function (webpack may provide a broken polyfill)
45
+ if (urlModule && typeof urlModule.fileURLToPath === 'function') {
46
+ const __filename = urlModule.fileURLToPath(import.meta.url);
47
+ const computedDirname = path.dirname(__filename);
48
+ globalThis.__dirnameCache = computedDirname;
49
+ return computedDirname;
50
+ }
51
+ }
52
+ catch (error) {
53
+ // If webpack provides a broken polyfill or require fails, return empty
54
+ // __dirname will be computed when the plugin function is called (server-side only)
55
+ return '';
56
+ }
57
+ return '';
58
+ }
59
+ // Initialize __dirname at module load time, but handle webpack bundling gracefully
60
+ let __dirname = '';
61
+ let peerDepsValidated = false;
62
+ try {
63
+ // Only compute __dirname if we're in Node.js (not during webpack bundling)
64
+ if (typeof process !== 'undefined' && ((_a = process.versions) === null || _a === void 0 ? void 0 : _a.node)) {
65
+ // In Jest/Babel transformed environment, __filename is available
66
+ // @ts-ignore - __filename is available after Babel transforms ES modules to CommonJS
67
+ if (typeof __filename !== 'undefined') {
68
+ __dirname = path.dirname(__filename);
69
+ validatePeerDependencies(__dirname);
70
+ peerDepsValidated = true;
71
+ }
72
+ else {
73
+ // Check if import.meta.url is available - use try-catch since import.meta might be undefined
74
+ let hasImportMetaUrl = false;
75
+ try {
76
+ hasImportMetaUrl = typeof import.meta.url !== 'undefined';
77
+ }
78
+ catch {
79
+ // import.meta is undefined (e.g., in Jest environment before Babel transform)
80
+ hasImportMetaUrl = false;
81
+ }
82
+ if (hasImportMetaUrl) {
83
+ const require = createRequire(import.meta.url);
84
+ const urlModule = require('url');
85
+ // Check if fileURLToPath is actually a function (not a webpack polyfill)
86
+ if (urlModule && typeof urlModule.fileURLToPath === 'function') {
87
+ const __filename = urlModule.fileURLToPath(import.meta.url);
88
+ __dirname = path.dirname(__filename);
89
+ validatePeerDependencies(__dirname);
90
+ peerDepsValidated = true;
91
+ }
92
+ }
93
+ }
94
+ }
95
+ }
96
+ catch {
97
+ // If initialization fails (e.g., during webpack bundling), __dirname will be empty
98
+ // and will be computed lazily via getDirname() when needed
99
+ }
100
+ // Validate peer dependencies lazily if not already validated
101
+ if (!peerDepsValidated && typeof process !== 'undefined' && ((_b = process.versions) === null || _b === void 0 ? void 0 : _b.node)) {
102
+ try {
103
+ const dirname = getDirname();
104
+ if (dirname) {
105
+ validatePeerDependencies(dirname);
106
+ peerDepsValidated = true;
107
+ }
108
+ }
109
+ catch {
110
+ // Ignore validation errors during webpack bundling
111
+ }
112
+ }
113
+ /**
114
+ * Docusaurus Glossary Plugin
115
+ *
116
+ * A plugin that provides glossary functionality with:
117
+ * - Glossary terms defined in a JSON file
118
+ * - Auto-generated glossary page
119
+ * - GlossaryTerm component for inline definitions
120
+ * - Tooltips on hover
121
+ * - Automatic glossary term detection in markdown files (requires manual remark plugin configuration)
122
+ *
123
+ * IMPORTANT: To enable auto-linking of glossary terms, you must manually add the remark plugin
124
+ * to your docusaurus.config.js using the getRemarkPlugin helper:
125
+ *
126
+ * Example:
127
+ * ```javascript
128
+ * const glossaryPlugin = require('docusaurus-plugin-glossary');
129
+ *
130
+ * module.exports = {
131
+ * presets: [
132
+ * ['@docusaurus/preset-classic', {
133
+ * docs: {
134
+ * remarkPlugins: [
135
+ * glossaryPlugin.getRemarkPlugin({
136
+ * glossaryPath: 'glossary/glossary.json',
137
+ * routePath: '/glossary',
138
+ * }, { siteDir: __dirname }),
139
+ * ],
140
+ * },
141
+ * pages: {
142
+ * remarkPlugins: [
143
+ * glossaryPlugin.getRemarkPlugin({
144
+ * glossaryPath: 'glossary/glossary.json',
145
+ * routePath: '/glossary',
146
+ * }, { siteDir: __dirname }),
147
+ * ],
148
+ * },
149
+ * }],
150
+ * ],
151
+ * plugins: [
152
+ * ['docusaurus-plugin-glossary', {
153
+ * glossaryPath: 'glossary/glossary.json',
154
+ * routePath: '/glossary',
155
+ * }],
156
+ * ],
157
+ * };
158
+ * ```
159
+ *
160
+ * @param context - Docusaurus context
161
+ * @param options - Plugin options
162
+ * @param options.glossaryPath - Path to glossary JSON file (default: 'glossary/glossary.json')
163
+ * @param options.routePath - Route path for glossary page (default: '/glossary')
164
+ * @param options.autoLinkTerms - Legacy option, kept for compatibility but no longer used (configure remark plugin manually instead)
165
+ * @returns Plugin object
166
+ */
167
+ export default function glossaryPlugin(context, options = {}) {
168
+ const { glossaryPath = 'glossary/glossary.json', routePath = '/glossary', autoLinkTerms = true, } = options;
169
+ let glossaryDataCache = { terms: [] };
170
+ return {
171
+ name: 'docusaurus-plugin-glossary',
172
+ async loadContent() {
173
+ // Load glossary terms from JSON file
174
+ const glossaryFilePath = path.resolve(context.siteDir, glossaryPath);
175
+ if (await fs.pathExists(glossaryFilePath)) {
176
+ const glossaryData = (await fs.readJson(glossaryFilePath));
177
+ glossaryDataCache = glossaryData;
178
+ return glossaryData;
179
+ }
180
+ console.warn(`Glossary file not found at ${glossaryFilePath}. Using empty glossary.`);
181
+ glossaryDataCache = { terms: [] };
182
+ return { terms: [] };
183
+ },
184
+ async contentLoaded({ content, actions }) {
185
+ const { createData, addRoute, setGlobalData } = actions;
186
+ const glossaryContent = content;
187
+ // Create data file that can be imported by components
188
+ const glossaryDataPath = await createData('glossary-data.json', JSON.stringify(glossaryContent));
189
+ // Create a data file for the remark plugin to access glossary terms
190
+ const remarkGlossaryDataPath = await createData('remark-glossary-data.json', JSON.stringify({
191
+ terms: glossaryContent.terms || [],
192
+ routePath: routePath,
193
+ }));
194
+ // Add glossary page route
195
+ // Compute __dirname if not already set (for webpack bundling compatibility)
196
+ const pluginDirname = __dirname || getDirname();
197
+ addRoute({
198
+ path: routePath,
199
+ component: path.join(pluginDirname, 'components/GlossaryPage.js'),
200
+ exact: true,
201
+ modules: {
202
+ glossaryData: glossaryDataPath,
203
+ },
204
+ });
205
+ // Expose global data for runtime lookups (used by GlossaryTerm)
206
+ setGlobalData({
207
+ terms: glossaryContent.terms || [],
208
+ routePath,
209
+ });
210
+ },
211
+ getThemePath() {
212
+ // Compute __dirname if not already set (for webpack bundling compatibility)
213
+ const pluginDirname = __dirname || getDirname();
214
+ return path.resolve(pluginDirname, './theme');
215
+ },
216
+ getPathsToWatch() {
217
+ return [path.resolve(context.siteDir, glossaryPath)];
218
+ },
219
+ async postBuild({ outDir }) {
220
+ // You can add any post-build steps here if needed
221
+ console.log('Glossary plugin: Build completed');
222
+ },
223
+ };
224
+ }
225
+ // Export remark plugin factory for use in markdown configuration
226
+ export const remarkPlugin = remarkGlossaryTerms;
227
+ /**
228
+ * Helper function to get the configured remark plugin
229
+ * This can be used in docusaurus.config.js markdown configuration
230
+ *
231
+ * @param pluginOptions - Plugin options from docusaurus.config.js
232
+ * @param context - Context with siteDir
233
+ * @returns Configured remark plugin
234
+ */
235
+ export function getRemarkPlugin(pluginOptions, context) {
236
+ const { glossaryPath = 'glossary/glossary.json', routePath = '/glossary' } = pluginOptions;
237
+ const siteDir = context === null || context === void 0 ? void 0 : context.siteDir;
238
+ return [
239
+ remarkGlossaryTerms,
240
+ {
241
+ glossaryPath,
242
+ routePath,
243
+ siteDir,
244
+ },
245
+ ];
246
+ }