@diplodoc/transform 4.69.0 → 4.69.2
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/dist/css/_yfm-only.css.map +1 -1
- package/dist/css/_yfm-only.min.css.map +1 -1
- package/dist/css/base.css.map +1 -1
- package/dist/css/base.min.css.map +1 -1
- package/dist/css/print.css +1 -1
- package/dist/css/print.css.map +3 -3
- package/dist/css/yfm.css.map +1 -1
- package/dist/css/yfm.min.css.map +1 -1
- package/dist/scss/print/code.scss +1 -1
- package/lib/plugins/term/index.js +98 -14
- package/lib/plugins/term/index.js.map +1 -1
- package/package.json +3 -3
- package/src/scss/print/code.scss +1 -1
- package/src/transform/plugins/term/index.ts +130 -14
package/src/scss/print/code.scss
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type StateCore from 'markdown-it/lib/rules_core/state_core';
|
|
2
|
+
import type StateInline from 'markdown-it/lib/rules_inline/state_inline';
|
|
2
3
|
import type Token from 'markdown-it/lib/token';
|
|
3
4
|
import type {MarkdownItPluginCb} from '../typings';
|
|
4
5
|
|
|
@@ -7,12 +8,129 @@ import {generateID} from '../utils';
|
|
|
7
8
|
import {termDefinitions} from './termDefinitions';
|
|
8
9
|
import {BASIC_TERM_REGEXP} from './constants';
|
|
9
10
|
|
|
11
|
+
function setTermAttrs(token: Token, termKey: string): void {
|
|
12
|
+
token.attrSet('class', 'yfm yfm-term_title');
|
|
13
|
+
token.attrSet('term-key', ':' + termKey);
|
|
14
|
+
token.attrSet('role', 'button');
|
|
15
|
+
token.attrSet('aria-describedby', ':' + termKey + '_element');
|
|
16
|
+
token.attrSet('tabindex', '0');
|
|
17
|
+
token.attrSet('id', generateID());
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface TermMatch {
|
|
21
|
+
labelEnd: number;
|
|
22
|
+
termId: string;
|
|
23
|
+
endPos: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Scans src for [text](*termId) starting at `start`.
|
|
28
|
+
*
|
|
29
|
+
* @param src - source string
|
|
30
|
+
* @param start - position of the opening `[`
|
|
31
|
+
* @param max - maximum position to scan
|
|
32
|
+
* @returns match info or null
|
|
33
|
+
*/
|
|
34
|
+
function matchTermPattern(src: string, start: number, max: number): TermMatch | null {
|
|
35
|
+
// Scan for closing ] (no nested [ allowed, matching the original regex)
|
|
36
|
+
let pos = start + 1;
|
|
37
|
+
while (
|
|
38
|
+
pos <= max &&
|
|
39
|
+
src.charCodeAt(pos) !== 0x5d /* ] */ &&
|
|
40
|
+
src.charCodeAt(pos) !== 0x5b /* [ */
|
|
41
|
+
) {
|
|
42
|
+
if (src.charCodeAt(pos) === 0x5c /* \ */) {
|
|
43
|
+
pos++;
|
|
44
|
+
}
|
|
45
|
+
pos++;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (pos > max || src.charCodeAt(pos) !== 0x5d /* ] */) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const labelEnd = pos;
|
|
53
|
+
if (labelEnd === start + 1) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Expect (*
|
|
58
|
+
pos = labelEnd + 1;
|
|
59
|
+
if (
|
|
60
|
+
pos + 1 > max ||
|
|
61
|
+
src.charCodeAt(pos) !== 0x28 /* ( */ ||
|
|
62
|
+
src.charCodeAt(pos + 1) !== 0x2a /* * */
|
|
63
|
+
) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
pos += 2;
|
|
67
|
+
|
|
68
|
+
// Read term id until )
|
|
69
|
+
const termIdStart = pos;
|
|
70
|
+
while (
|
|
71
|
+
pos <= max &&
|
|
72
|
+
src.charCodeAt(pos) !== 0x29 /* ) */ &&
|
|
73
|
+
src.charCodeAt(pos) !== 0x0a /* \n */
|
|
74
|
+
) {
|
|
75
|
+
pos++;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (pos > max || src.charCodeAt(pos) !== 0x29 /* ) */) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const termId = src.slice(termIdStart, pos);
|
|
83
|
+
if (!termId) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return {labelEnd, termId, endPos: pos + 1};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Inline rule that matches [text](*termId) for defined terms.
|
|
92
|
+
* Runs before the link rule so that * characters inside the
|
|
93
|
+
* pattern are consumed and never trigger emphasis.
|
|
94
|
+
*
|
|
95
|
+
* @param state - inline parser state
|
|
96
|
+
* @param silent - if true, only validate without creating tokens
|
|
97
|
+
* @returns true if the pattern was matched
|
|
98
|
+
*/
|
|
99
|
+
function termInlineRule(state: StateInline, silent: boolean): boolean {
|
|
100
|
+
if (state.src.charCodeAt(state.pos) !== 0x5b /* [ */ || !state.env.terms) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const match = matchTermPattern(state.src, state.pos, state.posMax);
|
|
105
|
+
if (!match || !state.env.terms[':' + match.termId]) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (silent) {
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const labelContent = state.src.slice(state.pos + 1, match.labelEnd).replace(/\\(.)/g, '$1');
|
|
114
|
+
|
|
115
|
+
const termOpen = state.push('term_open', 'i', 1);
|
|
116
|
+
setTermAttrs(termOpen, match.termId);
|
|
117
|
+
|
|
118
|
+
const textToken = state.push('text', '', 0);
|
|
119
|
+
textToken.content = labelContent;
|
|
120
|
+
|
|
121
|
+
state.push('term_close', 'i', -1);
|
|
122
|
+
|
|
123
|
+
state.pos = match.endPos;
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
|
|
10
127
|
const term: MarkdownItPluginCb = (md, options) => {
|
|
11
128
|
const escapeRE = md.utils.escapeRE;
|
|
12
129
|
const arrayReplaceAt = md.utils.arrayReplaceAt;
|
|
13
130
|
|
|
14
131
|
const {isLintRun} = options;
|
|
15
|
-
|
|
132
|
+
|
|
133
|
+
// Prevent * URLs from being parsed as regular links (backward compatibility)
|
|
16
134
|
const defaultLinkValidation = md.validateLink;
|
|
17
135
|
md.validateLink = function (url) {
|
|
18
136
|
if (url.startsWith('*')) {
|
|
@@ -22,8 +140,11 @@ const term: MarkdownItPluginCb = (md, options) => {
|
|
|
22
140
|
return defaultLinkValidation(url);
|
|
23
141
|
};
|
|
24
142
|
|
|
143
|
+
// Inline rule: handles [text](*termId) before emphasis can interfere with *
|
|
144
|
+
md.inline.ruler.before('link', 'term_inline', termInlineRule);
|
|
145
|
+
|
|
25
146
|
function termReplace(state: StateCore) {
|
|
26
|
-
let i, j, l, tokens, token, text, nodes, pos,
|
|
147
|
+
let i, j, l, tokens, token, text, nodes, pos, termMatch, currentToken;
|
|
27
148
|
|
|
28
149
|
const blockTokens = state.tokens;
|
|
29
150
|
|
|
@@ -61,7 +182,7 @@ const term: MarkdownItPluginCb = (md, options) => {
|
|
|
61
182
|
continue;
|
|
62
183
|
}
|
|
63
184
|
|
|
64
|
-
if (
|
|
185
|
+
if (currentToken.type !== 'text') {
|
|
65
186
|
continue;
|
|
66
187
|
}
|
|
67
188
|
|
|
@@ -87,23 +208,18 @@ const term: MarkdownItPluginCb = (md, options) => {
|
|
|
87
208
|
nodes.push(token);
|
|
88
209
|
}
|
|
89
210
|
|
|
90
|
-
while ((
|
|
91
|
-
const termTitle =
|
|
92
|
-
const termKey =
|
|
211
|
+
while ((termMatch = reg.exec(text))) {
|
|
212
|
+
const termTitle = termMatch[1];
|
|
213
|
+
const termKey = termMatch[3];
|
|
93
214
|
|
|
94
|
-
if (
|
|
215
|
+
if (termMatch.index > 0 || termMatch[1].length > 0) {
|
|
95
216
|
token = new state.Token('text', '', 0);
|
|
96
|
-
token.content = text.slice(pos,
|
|
217
|
+
token.content = text.slice(pos, termMatch.index);
|
|
97
218
|
nodes.push(token);
|
|
98
219
|
}
|
|
99
220
|
|
|
100
221
|
token = new state.Token('term_open', 'i', 1);
|
|
101
|
-
token
|
|
102
|
-
token.attrSet('term-key', ':' + termKey);
|
|
103
|
-
token.attrSet('role', 'button');
|
|
104
|
-
token.attrSet('aria-describedby', ':' + termKey + '_element');
|
|
105
|
-
token.attrSet('tabindex', '0');
|
|
106
|
-
token.attrSet('id', generateID());
|
|
222
|
+
setTermAttrs(token, termKey);
|
|
107
223
|
nodes.push(token);
|
|
108
224
|
|
|
109
225
|
token = new state.Token('text', '', 0);
|