Skip to content

Commit 5d6cfea

Browse files
committed
bugfix: Do not drop digits in inline style cards if they are not list
numbers Fixes reuseman#127
1 parent de73775 commit 5d6cfea

File tree

4 files changed

+117
-16
lines changed

4 files changed

+117
-16
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,6 @@ move.sh
3131

3232
# Test-vault
3333
docs/test-vault/.obsidian/workspace
34+
35+
# Coverage results
36+
coverage/

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
},
3636
"dependencies": {
3737
"@types/showdown": "^1.9.3",
38-
"showdown": "^1.9.1"
38+
"showdown": "^1.9.1",
39+
"ts-dedent": "^2.2.0"
3940
}
4041
}

src/conf/regex.ts

+26-15
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,10 @@ export class Regex {
3333
this.headingsRegex = /^ {0,3}(#{1,6}) +([^\n]+?) ?((?: *#\S+)*) *$/gim;
3434

3535
// Supported images https://publish.obsidian.md/help/How+to/Embed+files
36-
this.wikiImageLinks =
37-
/!\[\[(.*\.(?:png|jpg|jpeg|gif|bmp|svg|tiff)).*?\]\]/gim;
38-
this.markdownImageLinks =
39-
/!\[\]\((.*\.(?:png|jpg|jpeg|gif|bmp|svg|tiff)).*?\)/gim;
36+
this.wikiImageLinks = /!\[\[(.*\.(?:png|jpg|jpeg|gif|bmp|svg|tiff)).*?\]\]/gim;
37+
this.markdownImageLinks = /!\[\]\((.*\.(?:png|jpg|jpeg|gif|bmp|svg|tiff)).*?\)/gim;
4038

41-
this.wikiAudioLinks =
42-
/!\[\[(.*\.(?:mp3|webm|wav|m4a|ogg|3gp|flac)).*?\]\]/gim;
39+
this.wikiAudioLinks = /!\[\[(.*\.(?:mp3|webm|wav|m4a|ogg|3gp|flac)).*?\]\]/gim;
4340

4441
// https://regex101.com/r/eqnJeW/1
4542
this.obsidianCodeBlock = /(?:```(?:.*?\n?)+?```)(?:\n|$)/gim;
@@ -53,8 +50,7 @@ export class Regex {
5350
this.cardsToDelete = /^\s*(?:\n)(?:\^(\d{13}))(?:\n\s*?)?/gm;
5451

5552
// https://regex101.com/r/WxuFI2/1
56-
this.globalTagsSplitter =
57-
/\[\[(.*?)\]\]|#([\p{L}\d:\-_/]+)|([\p{L}\d:\-_/]+)/gimu;
53+
this.globalTagsSplitter = /\[\[(.*?)\]\]|#([\p{L}\d:\-_/]+)|([\p{L}\d:\-_/]+)/gimu;
5854
this.tagHierarchy = /\//gm;
5955

6056
// Cards
@@ -66,17 +62,31 @@ export class Regex {
6662
"(?:[/-]reverse)?)((?: *#[\\p{Number}\\p{Letter}\\-\\/_]+)*) *?\\n+((?:[^\\n]\\n?)*?(?=\\^\\d{13}|$))(?:\\^(\\d{13}))?";
6763
this.flashscardsWithTag = new RegExp(str, flags);
6864

69-
// https://regex101.com/r/8wmOo8/1
70-
const sepLongest = settings.inlineSeparator.length >= settings.inlineSeparatorReverse.length ? settings.inlineSeparator : settings.inlineSeparatorReverse;
71-
const sepShortest = settings.inlineSeparator.length < settings.inlineSeparatorReverse.length ? settings.inlineSeparator : settings.inlineSeparatorReverse;
65+
// https://regex101.com/r/8wmOo8/2
66+
const sepLongest =
67+
settings.inlineSeparator.length >= settings.inlineSeparatorReverse.length
68+
? settings.inlineSeparator
69+
: settings.inlineSeparatorReverse;
70+
const sepShortest =
71+
settings.inlineSeparator.length < settings.inlineSeparatorReverse.length
72+
? settings.inlineSeparator
73+
: settings.inlineSeparatorReverse;
7274
// sepLongest is the longest between the inlineSeparator and the inlineSeparatorReverse because if the order is ::|::: then always the first will be matched
7375
// sepShortest is the shortest
7476
if (settings.inlineID) {
7577
str =
76-
"( {0,3}[#]{0,6})?(?:(?:[\\t ]*)(?:\\d.|[-+*]|#{1,6}))?(.+?) ?(" + sepLongest + "|" + sepShortest + ") ?(.+?)((?: *#[\\p{Letter}\\-\\/_]+)+)?(?:\\s+\\^(\\d{13})|$)";
78+
"( {0,3}[#]{0,6})?(?:(?:[\\t ]*)(?:\\d\\.|[-+*]|#{1,6}))?(.+?) ?(" +
79+
sepLongest +
80+
"|" +
81+
sepShortest +
82+
") ?(.+?)((?: *#[\\p{Letter}\\-\\/_]+)+)?(?:\\s+\\^(\\d{13})|$)";
7783
} else {
7884
str =
79-
"( {0,3}[#]{0,6})?(?:(?:[\\t ]*)(?:\\d.|[-+*]|#{1,6}))?(.+?) ?(" + sepLongest + "|" + sepShortest + ") ?(.+?)((?: *#[\\p{Letter}\\-\\/_]+)+|$)(?:\\n\\^(\\d{13}))?";
85+
"( {0,3}[#]{0,6})?(?:(?:[\\t ]*)(?:\\d\\.|[-+*]|#{1,6}))?(.+?) ?(" +
86+
sepLongest +
87+
"|" +
88+
sepShortest +
89+
") ?(.+?)((?: *#[\\p{Letter}\\-\\/_]+)+|$)(?:\\n\\^(\\d{13}))?";
8090
}
8191
this.cardsInlineStyle = new RegExp(str, flags);
8292

@@ -89,9 +99,10 @@ export class Regex {
8999

90100
// https://regex101.com/r/cgtnLf/1
91101

92-
str = "( {0,3}[#]{0,6})?(?:(?:[\\t ]*)(?:\\d.|[-+*]|#{1,6}))?(.*?(==.+?==|\\{.+?\\}).*?)((?: *#[\\w\\-\\/_]+)+|$)(?:\n\\^(\\d{13}))?"
102+
str =
103+
"( {0,3}[#]{0,6})?(?:(?:[\\t ]*)(?:\\d.|[-+*]|#{1,6}))?(.*?(==.+?==|\\{.+?\\}).*?)((?: *#[\\w\\-\\/_]+)+|$)(?:\n\\^(\\d{13}))?";
93104
this.cardsClozeWholeLine = new RegExp(str, flags);
94-
105+
95106
this.singleClozeCurly = /((?:{)(?:(\d):?)?(.+?)(?:}))/g;
96107
this.singleClozeHighlight = /((?:==)(.+?)(?:==))/g;
97108

tests/regex.test.ts

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import dedent from "ts-dedent";
2+
import { Regex } from "../src/conf/regex";
3+
4+
describe("Regex class unit tests", () => {
5+
describe("inline card pattern", () => {
6+
it("should work with default settings", () => {
7+
const regex = new Regex({
8+
contextAwareMode: true,
9+
sourceSupport: false,
10+
codeHighlightSupport: false,
11+
inlineID: false,
12+
contextSeparator: " > ",
13+
deck: "Default",
14+
folderBasedDeck: true,
15+
flashcardsTag: "card",
16+
inlineSeparator: "::",
17+
inlineSeparatorReverse: ":::",
18+
defaultAnkiTag: "obsidian",
19+
ankiConnectPermission: false,
20+
});
21+
22+
type Match = [string, string];
23+
24+
const candidates: [string, Match[]][] = [
25+
["#Question :: Answer", [["Question", "Answer"]]],
26+
["Answer ::: Question", [["Answer", "Question"]]],
27+
["Question :: Answer ^123456789", [["Question", "Answer ^123456789"]]],
28+
["Question :: Answer ^123456789\n^123456789", [["Question", "Answer ^123456789"]]],
29+
// FIXME: should be "The question" instead of " The question"
30+
["## Question #card\n- The question :: Answer", [[" The question", "Answer"]]],
31+
["No match!", []],
32+
// FIXME: should be "Question 1" instead of " Question 1"
33+
[
34+
dedent`
35+
1. Question 1 :: Answer 1
36+
2. Question 2 :: Answer 2
37+
3. Question 3 :: Answer 3`,
38+
[
39+
[" Question 1", "Answer 1"],
40+
[" Question 2", "Answer 2"],
41+
[" Question 3", "Answer 3"],
42+
],
43+
],
44+
// FIXME: should be "Question 1" instead of " Question 1"
45+
[
46+
dedent`
47+
- Question 1 :: Answer 1
48+
- Question 2 :: Answer 2
49+
- Question 3 :: Answer 3`,
50+
[
51+
[" Question 1", "Answer 1"],
52+
[" Question 2", "Answer 2"],
53+
[" Question 3", "Answer 3"],
54+
],
55+
],
56+
[
57+
dedent`
58+
1. Item 1 :: A
59+
2. Item 2 :: B
60+
- Item 2a :: Ba
61+
- Item 2b :: Bb`,
62+
[
63+
[" Item 1", "A"],
64+
[" Item 2", "B"],
65+
[" Item 2a", "Ba"],
66+
[" Item 2b", "Bb"],
67+
],
68+
],
69+
// FIXME: should not match
70+
// ["no :::: match", []],
71+
["2000 :: answer", [["2000", "answer"]]],
72+
];
73+
74+
for (const [input, expected] of candidates) {
75+
const matches = [...input.matchAll(regex.cardsInlineStyle)];
76+
77+
expect(matches.length).toEqual(expected.length);
78+
expected.forEach((exp, i) => {
79+
const match = matches[i];
80+
expect(match[2]).toEqual(exp[0]);
81+
expect(match[4]).toEqual(exp[1]);
82+
});
83+
}
84+
});
85+
});
86+
});

0 commit comments

Comments
 (0)