Skip to content

Commit 05b59da

Browse files
Bugfix/spaces in headings (#5)
Resolve issue with replacements in title sequences mentioned in issue #6. * Add test + naive fix for title spacing issue * Update readme to reflect the current version * Add option to disable header word replacement
1 parent 22680e2 commit 05b59da

File tree

6 files changed

+106
-22
lines changed

6 files changed

+106
-22
lines changed

README.md

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=stijn-dejongh_docsify-glossary&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=stijn-dejongh_docsify-glossary)
44

5-
Simple Glossary for Docsify that replaces occurrences of the terms with links to the glossary.
5+
Simple Glossary for Docsify that replaces occurrences of words in text with links to the glossary definitions.
66
Forked from [TheGreenToaster/docsify-glossary](https://github.com/TheGreenToaster/docsify-glossary) as the original
77
project was unmaintained for over 3 years, to address a couple of usability issues with the original script.
88

@@ -19,20 +19,32 @@ An example usage can be found here [./example](./example), it is deployed automa
1919
1. Create a `_glossary.md` file in the root directory
2020
2. Populate the `_glossary.md` file with terms.
2121

22-
## Usage
22+
## Plugim Usage
2323

2424
* Terms must be predicated with a consistent markdown heading to get recognized by the glossary (see configuration)
25-
* Terms in the documentation must be surrounded by space to get replaced by the regular expression
2625
* Terms are replaced with links in the order that they appear in the glossary file.
26+
* This is especially relevant for nested terminology ( e.g. _API_ and _API Usage_)
2727

28-
## Example
28+
## Running the code
2929

30-
1. Run `npm run-script build`
31-
2. Run `docsify serve example`
30+
In order to run the code, you will need a node set-up on your local machine.
31+
We recommend using [Node Version Manager](https://npm.github.io/installation-setup-docs/installing/using-a-node-version-manager.html) to make this easier.
32+
33+
### Building the code
34+
35+
1. Globally install [docsify](https://docsify.js.org/#/quickstart): `npm i docsify-cli -g`
36+
2. From the project root directory, run: `npm install`
37+
3. To build the code, run: `npm run ci`
38+
4. THis will compile, test, and package the plugin
39+
40+
### View the example website
41+
42+
Once the code has been built, you can launch the example website illustrating the use of the glossary.
43+
In order to do so:
3244
3. Go to [http://localhost:3000/]()
3345

3446
## Changelog
35-
47+
Simple Glossary for Docsify
3648
An overview of all the changes made to this codebase can be found in the [CHANGELOG](./CHANGELOG.md) file included in this repository.
3749

3850
## TODO list
@@ -41,6 +53,10 @@ An overview of all the changes made to this codebase can be found in the [CHANGE
4153
* [x] add unit tests to the code to make this package more maintainable
4254
* [x] make glossary file name/location configurable, see [feature request #1](https://github.com/TheGreenToaster/docsify-glossary/issues/1)
4355
* [x] make terminology heading depth configurable, see [feature request #1](https://github.com/TheGreenToaster/docsify-glossary/issues/1)
44-
* [ ] fix issue with terminology replacements in page headers/titles, see: [bug report #6](https://github.com/TheGreenToaster/docsify-glossary/issues/6)
56+
* [x] fix issue with terminology replacements in page headers/titles, see: [bug report #6](https://github.com/TheGreenToaster/docsify-glossary/issues/6)
4557
* [ ] fix issue with terminology replacements in code blocks, see: [bug report #4](https://github.com/TheGreenToaster/docsify-glossary/issues/4)
46-
* [ ] fix issue with multiple word terms, see: [bug report #13]([bug report #13](https://github.com/TheGreenToaster/docsify-glossary/issues/13))
58+
* [x] fix issue with multiple word terms, see: [bug report #13]([bug report #13](https://github.com/TheGreenToaster/docsify-glossary/issues/13))
59+
60+
61+
1. copy the latest version of the code into the example website: `cp ./dist/@stijn-dejongh/docsify-glossary* ./example`
62+
2. Run `docsify serve example`

example/docsify-glossary.js

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,33 @@ this["@stijn-dejongh/docsify-glossary"] = this["@stijn-dejongh/docsify-glossary"
99

1010
this["@stijn-dejongh/docsify-glossary"].js = function(exports) {
1111
"use strict";
12-
function replaceTerm(term, content, term_id) {
13-
var link = " [$1](/_glossary?id=".concat(term_id, ")");
14-
var re = new RegExp("\\s(".concat(term, ")\\s"), "ig");
12+
function replaceTermInLine(term, contentLine, linkId) {
13+
var re = new RegExp("\\s(".concat(term, ")[\\s$]"), "ig");
1514
var reFullStop = new RegExp("\\s(".concat(term, ")."), "ig");
1615
var reComma = new RegExp("\\s(".concat(term, "),"), "ig");
17-
return content.replace(reComma, link + ",").replace(re, link + " ").replace(reFullStop, link + ".");
16+
var link = " [$1](/_glossary?id=".concat(linkId, ")");
17+
var replacement = contentLine.replace(reComma, link + ",").replace(re, link + " ").replace(reFullStop, link + ".");
18+
return isTitle(contentLine) ? replacement.replaceAll("[".concat(term, "]"), "[ ".concat(term, "]")) : replacement;
19+
}
20+
function isTitle(line) {
21+
return line.trim().startsWith("#");
22+
}
23+
function replaceTerm(content, term, linkId) {
24+
var contentLines = content.split("\n");
25+
var processedText = "";
26+
contentLines.forEach((function(line, _index) {
27+
var replacedLine = line.trim().length > 0 ? replaceTermInLine(term, line + " ", linkId).trimEnd() : line;
28+
processedText += replacedLine + "\n";
29+
}));
30+
return processedText;
1831
}
1932
function addLinks(content, terms, config) {
2033
var textWithReplacements = content;
2134
if (config.debug) {
2235
console.log("Adding links for terminology: ".concat(terms));
2336
}
2437
for (var term in terms) {
25-
textWithReplacements = replaceTerm(term, textWithReplacements, terms[term]);
38+
textWithReplacements = replaceTerm(textWithReplacements, term, terms[term]);
2639
}
2740
return textWithReplacements;
2841
}

example/docsify-glossary.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main/js/configuration.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export class GlossaryConfigurationBuilder {
55
terminologyHeading = '';
66
glossaryLocation = '';
77
debug = false;
8-
8+
replaceTitleTerms = true;
99
constructor() {
1010
this.terminologyHeading = DEFAULT_TERM_HEADING;
1111
this.glossaryLocation = DEFAULT_GLOSSARY_FILE_NAME;
@@ -26,6 +26,11 @@ export class GlossaryConfigurationBuilder {
2626
return this;
2727
}
2828

29+
withTitleTermReplacement(enableTitleTermReplacement) {
30+
this.replaceTitleTerms = enableTitleTermReplacement;
31+
return this;
32+
}
33+
2934
build() {
3035
return {...this};
3136
}
@@ -36,6 +41,7 @@ export function configFromYaml(configurationYaml) {
3641
.withTermHeading(configurationYaml.terminologyHeading ?? DEFAULT_TERM_HEADING)
3742
.withGlossaryLocation(configurationYaml.glossaryLocation ?? DEFAULT_GLOSSARY_FILE_NAME)
3843
.withDebugEnabled(configurationYaml.debug ?? false)
44+
.withTitleTermReplacement(configurationYaml.replaceTitleTerms ?? true)
3945
.build();
4046
}
4147

src/main/js/glossary.js

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,36 @@
1-
export function replaceTerm(term, content, term_id) {
2-
let link = ` [$1](/_glossary?id=${term_id})`;
1+
function replaceTermInLine(term, contentLine, linkId, config) {
2+
if(isTitle(contentLine) && !config.replaceTitleTerms) {
3+
// Intentially not combined in the return statement, to avoid superfluous calculations
4+
return contentLine;
5+
}
6+
7+
let re = new RegExp(`\\s(${term})[\\s$]`, 'ig');
38

4-
let re = new RegExp(`\\s(${term})\\s`, 'ig');
59
let reFullStop = new RegExp(`\\s(${term}).`, 'ig');
610
let reComma = new RegExp(`\\s(${term}),`, 'ig');
711

8-
return content
9-
.replace(reComma, link + ',')
12+
let link = ` [$1](/_glossary?id=${linkId})`;
13+
14+
let replacement = contentLine.replace(reComma, link + ',')
1015
.replace(re, link + ' ')
1116
.replace(reFullStop, link + '.');
17+
18+
return isTitle(contentLine) ? replacement.replaceAll(`[${term}]`, `[ ${term}]`): replacement;
19+
}
20+
21+
function isTitle(line) {
22+
return line.trim().startsWith('#');
23+
}
24+
25+
export function replaceTerm(content, term, linkId, config) {
26+
let contentLines = content.split('\n');
27+
let processedText = '';
28+
29+
contentLines.forEach( (line, _index) => {
30+
let replacedLine = line.trim().length > 0 ? replaceTermInLine(term, line + ' ', linkId, config).trimEnd() : line;
31+
processedText += replacedLine + '\n';
32+
});
33+
return processedText;
1234
}
1335

1436
export function addLinks(content, terms, config) {
@@ -17,7 +39,7 @@ export function addLinks(content, terms, config) {
1739
console.log(`Adding links for terminology: ${terms}`);
1840
}
1941
for (let term in terms) {
20-
textWithReplacements = replaceTerm(term, textWithReplacements, terms[term]);
42+
textWithReplacements = replaceTerm(textWithReplacements, term, terms[term], config);
2143
}
2244
return textWithReplacements;
2345
}

src/test/js/glossary_test.spec.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,5 +96,32 @@ describe('Glossary terminology injection', () => {
9696

9797
expect([...result.matchAll('/_glossary\\?id=api')]).toHaveLength(5);
9898
});
99+
100+
it('preserves spaces in title sequences', () => {
101+
const textWithTitle = `
102+
## Information about the API
103+
104+
Some API is configured to use another API.
105+
`;
106+
107+
const result = addLinks(textWithTitle, dictionary, config);
108+
109+
expect(result).toContain('## Information about the [ API](/_glossary?id=api)');
110+
});
111+
112+
it('Word replacement in title sequences can be disabled', () => {
113+
const textWithTile = `
114+
# This is an API title
115+
116+
This is a paragraph of text, explaing stuff and mentioning the term API.
117+
`;
118+
119+
const configuration = glossifyConfig().withTitleTermReplacement(false)
120+
.build();
121+
122+
let result = addLinks(textWithTile, dictionary, configuration);
123+
124+
expect(result).toContain('# This is an API title');
125+
});
99126
});
100127

0 commit comments

Comments
 (0)