@diplodoc/transform 4.73.3 → 4.74.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/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.map +1 -1
- package/dist/css/yfm.css +14 -15
- package/dist/css/yfm.css.map +3 -3
- package/dist/css/yfm.min.css +1 -1
- package/dist/css/yfm.min.css.map +3 -3
- package/dist/js/base.js +6 -6
- package/dist/js/base.js.map +2 -2
- package/dist/js/base.min.js +1 -1
- package/dist/js/base.min.js.map +2 -2
- package/dist/js/yfm.js +117 -105
- package/dist/js/yfm.js.map +3 -3
- package/dist/js/yfm.min.js +1 -1
- package/dist/js/yfm.min.js.map +3 -3
- package/lib/md.js +3 -1
- package/lib/md.js.map +1 -1
- package/lib/plugins/code.js +9 -3
- package/lib/plugins/code.js.map +1 -1
- package/lib/plugins/images/index.d.ts +2 -1
- package/lib/plugins/images/index.js +4 -3
- package/lib/plugins/images/index.js.map +1 -1
- package/lib/plugins/inline-code/index.js +4 -7
- package/lib/plugins/inline-code/index.js.map +1 -1
- package/lib/plugins/tabs.d.ts +1 -0
- package/lib/plugins/term/index.js +32 -27
- package/lib/plugins/term/index.js.map +1 -1
- package/lib/plugins/utils.d.ts +10 -1
- package/lib/plugins/utils.js +16 -3
- package/lib/plugins/utils.js.map +1 -1
- package/lib/typings.d.ts +11 -0
- package/package.json +3 -3
- package/src/js/tooltip/tooltip.ts +7 -7
- package/src/js/tooltip/types.ts +0 -1
- package/src/transform/md.ts +3 -0
- package/src/transform/plugins/code.ts +15 -4
- package/src/transform/plugins/images/index.ts +12 -3
- package/src/transform/plugins/inline-code/index.ts +4 -9
- package/src/transform/plugins/term/index.ts +32 -27
- package/src/transform/plugins/utils.ts +15 -2
- package/src/transform/typings.ts +11 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/* eslint-disable max-len */
|
|
2
2
|
|
|
3
3
|
import type {MarkdownItPluginCb} from './typings';
|
|
4
|
+
import type {IDGenerator} from './utils';
|
|
4
5
|
|
|
5
|
-
import {generateID} from './utils';
|
|
6
|
+
import {generateID as globalGenerateID} from './utils';
|
|
6
7
|
|
|
7
8
|
const wrapInFloatingContainer = (
|
|
8
9
|
element: string | undefined,
|
|
@@ -72,7 +73,12 @@ interface EnvTerm {
|
|
|
72
73
|
};
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
function termReplace(
|
|
76
|
+
function termReplace(
|
|
77
|
+
str: string,
|
|
78
|
+
env: EnvTerm,
|
|
79
|
+
escape: (str: string) => string,
|
|
80
|
+
generateID: IDGenerator,
|
|
81
|
+
): string {
|
|
76
82
|
const regTerms = Object.keys(env.terms)
|
|
77
83
|
.map((el) => el.slice(1))
|
|
78
84
|
.map(escape)
|
|
@@ -83,7 +89,7 @@ function termReplace(str: string, env: EnvTerm, escape: (str: string) => string)
|
|
|
83
89
|
const termCode = str.replace(
|
|
84
90
|
reg,
|
|
85
91
|
(_match: string, p1: string, _p2: string, p3: string) =>
|
|
86
|
-
`<i class="yfm yfm-term_title" term-key=":${p3}" id="${generateID()}">${p1}</i>`,
|
|
92
|
+
`<i class="yfm yfm-term_title" term-key=":${p3}" id="${generateID(p3)}">${p1}</i>`,
|
|
87
93
|
);
|
|
88
94
|
|
|
89
95
|
return termCode || str;
|
|
@@ -100,6 +106,8 @@ const SPAN_TAG_RE = /<span[^>]*>|<\/span>/g;
|
|
|
100
106
|
* `['<span class="hljs-string">\'line1', 'line2\'</span>']`
|
|
101
107
|
* After:
|
|
102
108
|
* `['<span class="hljs-string">\'line1</span>', '<span class="hljs-string">line2\'</span>']`
|
|
109
|
+
* @param lines - Highlighted HTML split into separate lines.
|
|
110
|
+
* @returns Lines with balanced `<span>` tags on each line.
|
|
103
111
|
*/
|
|
104
112
|
function balanceSpansPerLine(lines: string[]): string[] {
|
|
105
113
|
const openTagStack: string[] = [];
|
|
@@ -152,6 +160,7 @@ type CodeOptions = {
|
|
|
152
160
|
|
|
153
161
|
const code: MarkdownItPluginCb<CodeOptions> = (md, opts) => {
|
|
154
162
|
const lineWrapping = opts?.codeLineWrapping || false;
|
|
163
|
+
const generateID = opts.generateID ?? globalGenerateID;
|
|
155
164
|
|
|
156
165
|
const superCodeRenderer = md.renderer.rules.fence;
|
|
157
166
|
md.renderer.rules.fence = function (tokens, idx, options, env, self) {
|
|
@@ -173,7 +182,9 @@ const code: MarkdownItPluginCb<CodeOptions> = (md, opts) => {
|
|
|
173
182
|
}
|
|
174
183
|
|
|
175
184
|
const superCodeWithTerms =
|
|
176
|
-
superCode && env?.terms
|
|
185
|
+
superCode && env?.terms
|
|
186
|
+
? termReplace(superCode, env, md.utils.escapeRE, generateID)
|
|
187
|
+
: superCode;
|
|
177
188
|
|
|
178
189
|
return wrapInFloatingContainer(superCodeWithTerms, idx, {lineWrapping});
|
|
179
190
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type Token from 'markdown-it/lib/token';
|
|
2
2
|
import type {MarkdownItPluginCb, MarkdownItPluginOpts} from '../typings';
|
|
3
3
|
import type {ImageOptions, StateCore} from '../../typings';
|
|
4
|
+
import type {IDGenerator} from '../utils';
|
|
4
5
|
|
|
5
6
|
import {join, sep} from 'path';
|
|
6
7
|
import {bold} from 'chalk';
|
|
@@ -9,6 +10,7 @@ import {readFileSync} from 'fs';
|
|
|
9
10
|
|
|
10
11
|
import {isFileExists, resolveRelativePath} from '../../utilsFS';
|
|
11
12
|
import {filterTokens, getSrcTokenAttr, isExternalHref} from '../../utils';
|
|
13
|
+
import {generateID as globalGenerateID} from '../utils';
|
|
12
14
|
|
|
13
15
|
const sanitizeAttribute = (value: string): string => value.replace(/(\d*[%a-z]{0,5}).*/gi, '$1');
|
|
14
16
|
|
|
@@ -166,7 +168,10 @@ const index: MarkdownItPluginCb<Opts> = (md, opts) => {
|
|
|
166
168
|
);
|
|
167
169
|
} else {
|
|
168
170
|
const svgToken = new state.Token('image_svg', '', 0);
|
|
169
|
-
svgToken.attrSet(
|
|
171
|
+
svgToken.attrSet(
|
|
172
|
+
'content',
|
|
173
|
+
replaceSvgContent(svgContent, imageOpts, opts.generateID),
|
|
174
|
+
);
|
|
170
175
|
childrenTokens[index] = svgToken;
|
|
171
176
|
}
|
|
172
177
|
}
|
|
@@ -193,7 +198,11 @@ const index: MarkdownItPluginCb<Opts> = (md, opts) => {
|
|
|
193
198
|
};
|
|
194
199
|
};
|
|
195
200
|
|
|
196
|
-
function replaceSvgContent(
|
|
201
|
+
function replaceSvgContent(
|
|
202
|
+
content: string | null,
|
|
203
|
+
options: ImageOptions,
|
|
204
|
+
generateID: IDGenerator = globalGenerateID,
|
|
205
|
+
) {
|
|
197
206
|
if (!content) {
|
|
198
207
|
return '';
|
|
199
208
|
}
|
|
@@ -239,7 +248,7 @@ function replaceSvgContent(content: string | null, options: ImageOptions) {
|
|
|
239
248
|
{
|
|
240
249
|
name: 'prefixIds',
|
|
241
250
|
params: {
|
|
242
|
-
prefix: '
|
|
251
|
+
prefix: generateID('svg'),
|
|
243
252
|
prefixClassNames: false,
|
|
244
253
|
},
|
|
245
254
|
},
|
|
@@ -2,20 +2,15 @@ import type {MarkdownItPluginCb} from '../../typings';
|
|
|
2
2
|
|
|
3
3
|
import {escapeHtml} from 'markdown-it/lib/common/utils';
|
|
4
4
|
|
|
5
|
-
import {generateID} from '../utils';
|
|
6
|
-
|
|
7
|
-
import {LANG_TOKEN_DESCRIPTION, LANG_TOKEN_LABEL} from './constant';
|
|
5
|
+
import {generateID as globalGenerateID} from '../utils';
|
|
8
6
|
|
|
9
7
|
const inlineCode: MarkdownItPluginCb = (md, options) => {
|
|
10
|
-
const
|
|
8
|
+
const generateID = options.generateID ?? globalGenerateID;
|
|
11
9
|
|
|
12
10
|
md.renderer.rules.code_inline = function (tokens, idx) {
|
|
13
|
-
const id = generateID();
|
|
14
|
-
|
|
15
|
-
const description = LANG_TOKEN_DESCRIPTION[lang] ?? LANG_TOKEN_DESCRIPTION.en;
|
|
16
|
-
const label = LANG_TOKEN_LABEL[lang] ?? LANG_TOKEN_LABEL.en;
|
|
11
|
+
const id = generateID('inline-code-id');
|
|
17
12
|
|
|
18
|
-
return `<code class="yfm-clipboard-inline-code" role="button"
|
|
13
|
+
return `<code class="yfm-clipboard-inline-code" role="button" tabindex='0' id="${id}">${escapeHtml(tokens[idx].content)}</code>`;
|
|
19
14
|
};
|
|
20
15
|
};
|
|
21
16
|
|
|
@@ -2,19 +2,20 @@ import type StateCore from 'markdown-it/lib/rules_core/state_core';
|
|
|
2
2
|
import type StateInline from 'markdown-it/lib/rules_inline/state_inline';
|
|
3
3
|
import type Token from 'markdown-it/lib/token';
|
|
4
4
|
import type {MarkdownItPluginCb} from '../typings';
|
|
5
|
+
import type {IDGenerator} from '../utils';
|
|
5
6
|
|
|
6
|
-
import {generateID} from '../utils';
|
|
7
|
+
import {generateID as globalGenerateID} from '../utils';
|
|
7
8
|
|
|
8
9
|
import {termDefinitions} from './termDefinitions';
|
|
9
10
|
import {BASIC_TERM_REGEXP} from './constants';
|
|
10
11
|
|
|
11
|
-
function setTermAttrs(token: Token, termKey: string): void {
|
|
12
|
+
function setTermAttrs(token: Token, termKey: string, generateID: IDGenerator): void {
|
|
12
13
|
token.attrSet('class', 'yfm yfm-term_title');
|
|
13
14
|
token.attrSet('term-key', ':' + termKey);
|
|
14
15
|
token.attrSet('role', 'button');
|
|
15
16
|
token.attrSet('aria-controls', ':' + termKey + '_element');
|
|
16
17
|
token.attrSet('tabindex', '0');
|
|
17
|
-
token.attrSet('id', generateID());
|
|
18
|
+
token.attrSet('id', generateID(termKey));
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
interface TermMatch {
|
|
@@ -88,38 +89,41 @@ function matchTermPattern(src: string, start: number, max: number): TermMatch |
|
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
/**
|
|
91
|
-
*
|
|
92
|
+
* Creates an inline rule that matches [text](*termId) for defined terms.
|
|
92
93
|
* Runs before the link rule so that * characters inside the
|
|
93
94
|
* pattern are consumed and never trigger emphasis.
|
|
94
95
|
*
|
|
95
|
-
* @param
|
|
96
|
-
* @
|
|
97
|
-
* @returns true if the pattern was matched
|
|
96
|
+
* @param generateID - per-file isolated ID generator
|
|
97
|
+
* @returns inline rule function for markdown-it
|
|
98
98
|
*/
|
|
99
|
-
function
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
99
|
+
function termInlineRuleFactory(generateID: IDGenerator) {
|
|
100
|
+
return function termInlineRule(state: StateInline, silent: boolean): boolean {
|
|
101
|
+
if (state.src.charCodeAt(state.pos) !== 0x5b /* [ */ || !state.env.terms) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
103
104
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
const match = matchTermPattern(state.src, state.pos, state.posMax);
|
|
106
|
+
if (!match || !state.env.terms[':' + match.termId]) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
108
109
|
|
|
109
|
-
|
|
110
|
-
|
|
110
|
+
if (!silent) {
|
|
111
|
+
const labelContent = state.src
|
|
112
|
+
.slice(state.pos + 1, match.labelEnd)
|
|
113
|
+
.replace(/\\(.)/g, '$1');
|
|
111
114
|
|
|
112
|
-
|
|
113
|
-
|
|
115
|
+
const termOpen = state.push('term_open', 'i', 1);
|
|
116
|
+
setTermAttrs(termOpen, match.termId, generateID);
|
|
114
117
|
|
|
115
|
-
|
|
116
|
-
|
|
118
|
+
const textToken = state.push('text', '', 0);
|
|
119
|
+
textToken.content = labelContent;
|
|
117
120
|
|
|
118
|
-
|
|
119
|
-
|
|
121
|
+
state.push('term_close', 'i', -1);
|
|
122
|
+
}
|
|
120
123
|
|
|
121
|
-
|
|
122
|
-
|
|
124
|
+
state.pos = match.endPos;
|
|
125
|
+
return true;
|
|
126
|
+
};
|
|
123
127
|
}
|
|
124
128
|
|
|
125
129
|
const RAW_CODE_TOKEN_TYPES = new Set(['fence', 'code_block', 'yfm_page-constructor']);
|
|
@@ -252,6 +256,7 @@ const term: MarkdownItPluginCb = (md, options) => {
|
|
|
252
256
|
const arrayReplaceAt = md.utils.arrayReplaceAt;
|
|
253
257
|
|
|
254
258
|
const {isLintRun} = options;
|
|
259
|
+
const generateID = options.generateID ?? globalGenerateID;
|
|
255
260
|
|
|
256
261
|
// Prevent * URLs from being parsed as regular links (backward compatibility)
|
|
257
262
|
const defaultLinkValidation = md.validateLink;
|
|
@@ -264,7 +269,7 @@ const term: MarkdownItPluginCb = (md, options) => {
|
|
|
264
269
|
};
|
|
265
270
|
|
|
266
271
|
// Inline rule: handles [text](*termId) before emphasis can interfere with *
|
|
267
|
-
md.inline.ruler.before('link', 'term_inline',
|
|
272
|
+
md.inline.ruler.before('link', 'term_inline', termInlineRuleFactory(generateID));
|
|
268
273
|
|
|
269
274
|
function termReplace(state: StateCore) {
|
|
270
275
|
let i, j, l, tokens, token, text, nodes, pos, termMatch, currentToken;
|
|
@@ -358,7 +363,7 @@ const term: MarkdownItPluginCb = (md, options) => {
|
|
|
358
363
|
}
|
|
359
364
|
|
|
360
365
|
token = new state.Token('term_open', 'i', 1);
|
|
361
|
-
setTermAttrs(token, termKey);
|
|
366
|
+
setTermAttrs(token, termKey, generateID);
|
|
362
367
|
nodes.push(token);
|
|
363
368
|
|
|
364
369
|
token = new state.Token('text', '', 0);
|
|
@@ -3,6 +3,8 @@ import type {Logger} from '../log';
|
|
|
3
3
|
|
|
4
4
|
import {bold} from 'chalk';
|
|
5
5
|
import {platform} from 'process';
|
|
6
|
+
export type {IDGenerator, IDGeneratorStrategy} from '@diplodoc/utils';
|
|
7
|
+
export {createIDGenerator, createIDGeneratorByStrategy} from '@diplodoc/utils';
|
|
6
8
|
|
|
7
9
|
export type MatchTokenFunction = (
|
|
8
10
|
tokens: Token[],
|
|
@@ -34,8 +36,19 @@ export const nestedCloseTokenIdxFactory =
|
|
|
34
36
|
|
|
35
37
|
export const сarriage = platform === 'win32' ? '\r\n' : '\n';
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Generates a legacy random ID.
|
|
41
|
+
* @deprecated Use `options.generateID` from plugin context instead.
|
|
42
|
+
* Fallback preserves legacy random behavior without shared counter state.
|
|
43
|
+
* @param prefix - Optional prefix to prepend to the generated ID.
|
|
44
|
+
* @returns Random ID string, optionally prefixed with `${prefix}-`.
|
|
45
|
+
*/
|
|
46
|
+
export function generateID(prefix?: string): string {
|
|
47
|
+
if (!prefix) {
|
|
48
|
+
return Math.random().toString(36).substr(2, 8);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return `${prefix}-${Math.random().toString(36).substr(2, 8)}`;
|
|
39
52
|
}
|
|
40
53
|
|
|
41
54
|
export function append<T extends Record<string, []>, Key extends keyof T>(
|
package/src/transform/typings.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type DefaultStateCore from 'markdown-it/lib/rules_core/state_core';
|
|
|
5
5
|
import type {SanitizeFunction, SanitizeOptions} from './sanitize';
|
|
6
6
|
import type {LogLevels, Logger} from './log';
|
|
7
7
|
import type {ChangelogItem} from './plugins/changelog/types';
|
|
8
|
+
import type {IDGenerator} from './plugins/utils';
|
|
8
9
|
|
|
9
10
|
export interface MarkdownIt extends DefaultMarkdownIt {
|
|
10
11
|
assets?: string[];
|
|
@@ -109,6 +110,15 @@ export interface OptionsType {
|
|
|
109
110
|
* @default false
|
|
110
111
|
*/
|
|
111
112
|
codeLineWrapping?: boolean;
|
|
113
|
+
/**
|
|
114
|
+
* Custom ID generator factory to use for this transform call.
|
|
115
|
+
* If provided, it will be called once per file to create a per-file isolated generator.
|
|
116
|
+
* If not provided, a new {@link IDGenerator} is created via {@link createIDGenerator}
|
|
117
|
+
* (deterministic per-file counters).
|
|
118
|
+
*
|
|
119
|
+
* Pass `() => () => Math.random().toString(36).substr(2, 8)` to restore legacy random behavior.
|
|
120
|
+
*/
|
|
121
|
+
generateID?: IDGenerator;
|
|
112
122
|
}
|
|
113
123
|
|
|
114
124
|
export interface OutputType {
|
|
@@ -134,6 +144,7 @@ export interface MarkdownItPluginOpts {
|
|
|
134
144
|
root: string;
|
|
135
145
|
rootPublicPath: string;
|
|
136
146
|
isLintRun: boolean;
|
|
147
|
+
generateID?: IDGenerator;
|
|
137
148
|
cache?: CacheContext;
|
|
138
149
|
conditionsInCode?: boolean;
|
|
139
150
|
vars?: Record<string, string>;
|