@diplodoc/transform 4.76.10 → 4.77.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.
Files changed (43) hide show
  1. package/dist/css/_yfm-only.css +2 -0
  2. package/dist/css/_yfm-only.css.map +3 -3
  3. package/dist/css/_yfm-only.min.css +1 -1
  4. package/dist/css/_yfm-only.min.css.map +3 -3
  5. package/dist/css/base.css +7 -0
  6. package/dist/css/base.css.map +3 -3
  7. package/dist/css/base.min.css +1 -1
  8. package/dist/css/base.min.css.map +3 -3
  9. package/dist/css/print.css.map +1 -1
  10. package/dist/css/yfm.css +9 -0
  11. package/dist/css/yfm.css.map +3 -3
  12. package/dist/css/yfm.min.css +1 -1
  13. package/dist/css/yfm.min.css.map +3 -3
  14. package/dist/js/_yfm-only.js +4 -0
  15. package/dist/js/_yfm-only.js.map +2 -2
  16. package/dist/js/_yfm-only.min.js +1 -1
  17. package/dist/js/_yfm-only.min.js.map +2 -2
  18. package/dist/js/base.js +19 -6
  19. package/dist/js/base.js.map +2 -2
  20. package/dist/js/base.min.js +3 -1
  21. package/dist/js/base.min.js.map +3 -3
  22. package/dist/js/yfm.js +23 -6
  23. package/dist/js/yfm.js.map +2 -2
  24. package/dist/js/yfm.min.js +3 -1
  25. package/dist/js/yfm.min.js.map +3 -3
  26. package/dist/scss/_code.scss +6 -0
  27. package/dist/scss/_term.scss +8 -0
  28. package/lib/plugins/code.js +110 -17
  29. package/lib/plugins/code.js.map +1 -1
  30. package/lib/plugins/links/index.d.ts +1 -1
  31. package/lib/utils.js +4 -1
  32. package/lib/utils.js.map +1 -1
  33. package/package.json +2 -1
  34. package/src/js/anchor.ts +1 -1
  35. package/src/js/code.ts +28 -11
  36. package/src/js/constant.ts +1 -1
  37. package/src/js/inline-code/index.ts +1 -1
  38. package/src/js/term/utils.ts +10 -0
  39. package/src/scss/_code.scss +6 -0
  40. package/src/scss/_term.scss +8 -0
  41. package/src/transform/plugins/code.ts +140 -17
  42. package/src/transform/plugins/links/index.ts +1 -1
  43. package/src/transform/utils.ts +4 -1
@@ -21,6 +21,14 @@
21
21
  visibility: hidden;
22
22
  opacity: 0;
23
23
 
24
+ // Keep the closed definition off-screen so its (still laid-out) box
25
+ // does not extend the page's scrollable area. Inline top/left set by
26
+ // setDefinitionPosition() are cleared in closeDefinition() to restore
27
+ // these values. Negative-direction overflow does not create a
28
+ // scrollable region, while the box stays measurable for positioning.
29
+ top: -9999px;
30
+ left: -9999px;
31
+
24
32
  padding: 10px;
25
33
 
26
34
  background-color: var(
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  /* eslint-disable max-len */
3
- const utils_1 = require("./utils");
3
+ const utils_1 = require("markdown-it/lib/common/utils");
4
+ const utils_2 = require("./utils");
4
5
  const wrapInFloatingContainer = (element, id, lineWrapping) => {
5
6
  const wrappingButton = lineWrapping
6
7
  ? `<button role="button" class="g-button g-button_view_flat g-button_size_m g-button_pin_round-round g-md-viewer-code-button yfm-code-button yfm-wrapping-button" tabindex="-1" type="button" aria-label="Toggle line wrapping" aria-pressed="false" data-tabindex="0">
@@ -102,7 +103,38 @@ function balanceSpansPerLine(lines) {
102
103
  return prefix + line + suffix;
103
104
  });
104
105
  }
105
- function addLineNumbers(code, { lineWrapping }) {
106
+ /**
107
+ * Strips the prompt prefix from the raw fence content BEFORE it reaches the highlighter.
108
+ *
109
+ * @param content - Raw fence content.
110
+ * @param prompt - Raw prompt string (e.g. `$`, `#`, `>>>`).
111
+ * @returns Stripped content (same number of lines) and a per-line prompt flag array.
112
+ */
113
+ function stripPrompt(content, prompt) {
114
+ const hasTrailingNewline = content.endsWith('\n');
115
+ const lines = content.split('\n');
116
+ const linesToProcess = hasTrailingNewline ? lines.slice(0, -1) : lines;
117
+ const flags = [];
118
+ const stripped = linesToProcess.map((line) => {
119
+ const trimmed = line.trimStart();
120
+ const leadingWs = line.slice(0, line.length - trimmed.length);
121
+ if (trimmed.startsWith(prompt + ' ')) {
122
+ flags.push(true);
123
+ return leadingWs + trimmed.slice(prompt.length + 1);
124
+ }
125
+ if (trimmed === prompt) {
126
+ flags.push(true);
127
+ return leadingWs;
128
+ }
129
+ flags.push(false);
130
+ return line;
131
+ });
132
+ return {
133
+ content: stripped.join('\n') + (hasTrailingNewline ? '\n' : ''),
134
+ flags,
135
+ };
136
+ }
137
+ function postProcessCode(code, { showLineNumbers, lineWrapping, promptFlags, promptEscaped, }) {
106
138
  const hasTrailingNewline = code.endsWith('\n');
107
139
  const lines = code.split('\n');
108
140
  const linesToProcess = hasTrailingNewline ? lines.slice(0, -1) : lines;
@@ -110,41 +142,102 @@ function addLineNumbers(code, { lineWrapping }) {
110
142
  const maxDigits = String(normalized.length).length;
111
143
  return (normalized
112
144
  .map((line, index) => {
113
- const lineNumber = String(index + 1).padStart(maxDigits, ' ');
114
- return lineWrapping
115
- ? `<span class="yfm-line-number">${lineNumber}</span><span class="yfm-line">${line}</span>`
116
- : `<span class="yfm-line-number">${lineNumber}</span>${line}`;
145
+ // The prompt was already stripped from the raw content before
146
+ // highlighting, so `line` here is the highlighted command only.
147
+ // Re-insert the prompt as a dedicated, non-selectable span after
148
+ // any leading whitespace. `promptFlags` marks which lines carried
149
+ // a prompt in the original source.
150
+ if ((promptFlags === null || promptFlags === void 0 ? void 0 : promptFlags[index]) && promptEscaped !== undefined) {
151
+ const trimmed = line.trimStart();
152
+ const leadingWs = line.slice(0, line.length - trimmed.length);
153
+ line =
154
+ `${leadingWs}` +
155
+ `<span class="yfm-code-prompt" aria-hidden="true">${promptEscaped} </span>` +
156
+ `${trimmed}`;
157
+ }
158
+ if (showLineNumbers) {
159
+ const lineNumber = String(index + 1).padStart(maxDigits, ' ');
160
+ line = lineWrapping
161
+ ? `<span class="yfm-line-number">${lineNumber}</span><span class="yfm-line">${line}</span>`
162
+ : `<span class="yfm-line-number">${lineNumber}</span>${line}`;
163
+ }
164
+ return line;
117
165
  })
118
166
  .join('\n') + (hasTrailingNewline ? '\n' : ''));
119
167
  }
168
+ /**
169
+ * @param info - Raw fence info string (e.g. `js showLineNumbers prompt="$"`).
170
+ * @returns Parsed flags and the optional prompt value.
171
+ */
172
+ function parseFenceInfo(info) {
173
+ var _a;
174
+ const promptMatch = /(?:^|\s)prompt=(?:"([^"]*)"|'([^']*)')/.exec(info);
175
+ const prompt = (_a = promptMatch === null || promptMatch === void 0 ? void 0 : promptMatch[1]) !== null && _a !== void 0 ? _a : promptMatch === null || promptMatch === void 0 ? void 0 : promptMatch[2];
176
+ const rest = promptMatch ? info.replace(promptMatch[0], ' ') : info;
177
+ return {
178
+ showLineNumbers: /\bshowLineNumbers\b/.test(rest),
179
+ wrapLines: /\bwrap\b/.test(rest),
180
+ prompt,
181
+ };
182
+ }
120
183
  const code = (md, opts) => {
121
184
  var _a;
122
185
  const lineWrapping = (opts === null || opts === void 0 ? void 0 : opts.codeLineWrapping) || false;
123
- const generateID = (_a = opts.generateID) !== null && _a !== void 0 ? _a : utils_1.generateID;
186
+ const generateID = (_a = opts === null || opts === void 0 ? void 0 : opts.generateID) !== null && _a !== void 0 ? _a : utils_2.generateID;
124
187
  const superCodeRenderer = md.renderer.rules.fence;
125
188
  md.renderer.rules.fence = function (tokens, idx, options, env, self) {
126
189
  const token = tokens[idx];
127
- const showLineNumbers = token.info.includes('showLineNumbers');
128
- const wrapLines = token.info.includes('wrap');
190
+ const { showLineNumbers, prompt, wrapLines } = parseFenceInfo(token.info);
129
191
  const shouldWrap = wrapLines;
192
+ // Strip the prompt prefix from the raw content BEFORE handing it
193
+ // to the highlighter, so language grammars never misinterpret prompt
194
+ // symbols (e.g. `#` as a shell comment, `$` as a variable). The prompt is
195
+ // re-inserted as a span in postProcessCode, driven by `promptFlags`.
196
+ let promptFlags;
197
+ let promptEscaped;
198
+ const originalContent = token.content;
199
+ if (prompt) {
200
+ const stripped = stripPrompt(token.content, prompt);
201
+ token.content = stripped.content;
202
+ promptFlags = stripped.flags;
203
+ promptEscaped = (0, utils_1.escapeHtml)(prompt);
204
+ }
130
205
  let superCode = superCodeRenderer === null || superCodeRenderer === void 0 ? void 0 : superCodeRenderer(tokens, idx, options, env, self);
131
- if (superCode && showLineNumbers) {
206
+ // Restore the original content so the mutation does not leak to other
207
+ // consumers of the token.
208
+ token.content = originalContent;
209
+ if (superCode && (showLineNumbers || prompt)) {
132
210
  // Extract the code content from the pre/code tags
133
211
  const codeMatch = superCode.match(/<pre[^>]*><code[^>]*>([\s\S]*?)<\/code><\/pre>/);
134
212
  if (codeMatch) {
135
213
  const codeContent = codeMatch[1];
136
- const codeWithLineNumbers = addLineNumbers(codeContent, { lineWrapping });
214
+ const processedCode = postProcessCode(codeContent, {
215
+ showLineNumbers,
216
+ lineWrapping,
217
+ promptFlags,
218
+ promptEscaped,
219
+ });
137
220
  // Escape $ in replacement string: $$ becomes a literal $ in String.replace()
138
- const escapedReplacement = codeWithLineNumbers.replace(/\$/g, '$$$$');
221
+ const escapedReplacement = processedCode.replace(/\$/g, '$$$$');
139
222
  superCode = superCode.replace(codeContent, escapedReplacement);
140
223
  }
141
224
  }
142
- if (superCode && shouldWrap) {
143
- superCode = superCode.replace(/<code([^>]*)>/, (_match, attrs) => {
144
- if (attrs.includes('class=')) {
145
- return `<code${attrs.replace(/class="([^"]*)"/, 'class="$1 wrap"')}>`;
225
+ // Attach the raw prompt value as a data attribute on <code> so that the
226
+ // copy widget can strip it from the plain-text content without relying on
227
+ // any class names or DOM structure introduced by the plugin.
228
+ if (superCode && (prompt || shouldWrap)) {
229
+ superCode = superCode.replace(/(<pre[^>]*><code)([^>]*)>/, (_match, open, attrs) => {
230
+ // Add the wrap class
231
+ if (shouldWrap) {
232
+ attrs = /class="[^"]*"/.test(attrs)
233
+ ? attrs.replace(/class="([^"]*)"/, 'class="$1 wrap"')
234
+ : ` class="wrap"${attrs}`;
235
+ }
236
+ // Add the data-prompt attribute
237
+ if (prompt) {
238
+ attrs = ` data-prompt="${(0, utils_1.escapeHtml)(prompt)}"${attrs}`;
146
239
  }
147
- return `<code class="wrap"${attrs}>`;
240
+ return `${open}${attrs}>`;
148
241
  });
149
242
  }
150
243
  const superCodeWithTerms = superCode && (env === null || env === void 0 ? void 0 : env.terms)
@@ -1 +1 @@
1
- {"version":3,"file":"code.js","sourceRoot":"","sources":["../../src/transform/plugins/code.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"code.js","sourceRoot":"","sources":["../../src/transform/plugins/code.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import type Token from 'markdown-it/lib/token';
2
- import type { Logger } from 'src/transform/log';
2
+ import type { Logger } from '../../log';
3
3
  import type { CacheContext, StateCore } from '../../typings';
4
4
  import type { MarkdownItPluginCb, MarkdownItPluginOpts } from '../typings';
5
5
  type Options = {
package/lib/utils.js CHANGED
@@ -12,7 +12,10 @@ exports.defaultTransformLink = defaultTransformLink;
12
12
  exports.filterTokens = filterTokens;
13
13
  const utils_1 = require("@diplodoc/utils");
14
14
  function isLocalUrl(url) {
15
- return !/^(?:[a-z]+:)?\/\//i.test(url);
15
+ // A URL is local unless it has an external scheme: either `scheme://...`
16
+ // / `//host...` (protocol-relative), or an opaque scheme URI without
17
+ // a slash-slash part (e.g. `mailto:`, `tel:`, `custom:`).
18
+ return !isExternalHref(url);
16
19
  }
17
20
  function findBlockTokens(tokens, id) {
18
21
  let blockTokens = [];
package/lib/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/transform/utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/transform/utils.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diplodoc/transform",
3
- "version": "4.76.10",
3
+ "version": "4.77.1",
4
4
  "description": "A simple transformer of text in YFM (Yandex Flavored Markdown) to HTML",
5
5
  "keywords": [
6
6
  "markdown",
@@ -94,6 +94,7 @@
94
94
  "esbuild-sass-plugin": "^3.3.1",
95
95
  "highlight.js": "^11.8.0",
96
96
  "jest-serializer-html": "^7.1.0",
97
+ "jsdom": "^25.0.1",
97
98
  "markdown-it-testgen": "^0.1.6",
98
99
  "npm-run-all": "^4.1.5",
99
100
  "postcss": "^8.4.27",
package/src/js/anchor.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type {Lang} from 'src/transform/typings';
1
+ import type {Lang} from '../transform/typings';
2
2
 
3
3
  import {createTooltipFactory} from './tooltip';
4
4
  import {copyToClipboard, getEventTarget, isCustom} from './utils';
package/src/js/code.ts CHANGED
@@ -31,17 +31,34 @@ function buttonCopyFn(target: HTMLElement) {
31
31
  return;
32
32
  }
33
33
 
34
- // Get all text nodes and filter out line numbers
35
- const textContent = Array.from(code.childNodes)
36
- .filter((node) => {
37
- // Skip line number spans
38
- if (node instanceof HTMLElement && node.classList.contains('yfm-line-number')) {
39
- return false;
40
- }
41
- return true;
42
- })
43
- .map((node) => node.textContent)
44
- .join('');
34
+ // Strip line-number decorations (class-based, no semantic alternative).
35
+ const clone = code.cloneNode(true) as HTMLElement;
36
+
37
+ clone.querySelectorAll('.yfm-line-number').forEach((el) => el.remove());
38
+ let textContent = clone.textContent ?? '';
39
+
40
+ // Strip prompt prefix from each line using the raw value stored in data-prompt.
41
+ // This avoids any dependency on how (or whether) the prompt is wrapped in the DOM.
42
+ // Leading whitespace before the prompt is preserved so indented commands keep
43
+ // their indentation level in the copied text.
44
+ const promptValue = code.dataset.prompt;
45
+ if (promptValue) {
46
+ const prefix = promptValue + ' ';
47
+ textContent = textContent
48
+ .split('\n')
49
+ .map((line) => {
50
+ const trimmed = line.trimStart();
51
+ const leadingWs = line.slice(0, line.length - trimmed.length);
52
+ if (trimmed.startsWith(prefix)) {
53
+ return leadingWs + trimmed.slice(prefix.length);
54
+ }
55
+ if (trimmed === promptValue) {
56
+ return leadingWs;
57
+ }
58
+ return line;
59
+ })
60
+ .join('\n');
61
+ }
45
62
 
46
63
  copyToClipboard(textContent.trim()).then(() => {
47
64
  notifySuccess(container.querySelector('.yfm-clipboard-icon'));
@@ -1,4 +1,4 @@
1
- import type {Lang} from 'src/transform/typings';
1
+ import type {Lang} from '../transform/typings';
2
2
 
3
3
  export const COPIED_LANG_TOKEN: Record<Lang, string> = {
4
4
  ru: 'Скопировано',
@@ -1,4 +1,4 @@
1
- import type {Lang} from 'src/transform/typings';
1
+ import type {Lang} from '../../transform/typings';
2
2
 
3
3
  import {createTooltipFactory} from '../tooltip';
4
4
  import {copyToClipboard, getEventTarget, isCustom} from '../utils';
@@ -178,6 +178,16 @@ export function openDefinition(target: HTMLElement) {
178
178
 
179
179
  export function closeDefinition(definition: HTMLElement) {
180
180
  definition.classList.remove(openClass);
181
+
182
+ // Restore the off-screen position declared in CSS so the (still laid-out)
183
+ // definition box does not extend the page's scrollable area. Inline
184
+ // top/left were set by setDefinitionPosition() while the definition was
185
+ // open; without this reset they would keep the box in the document flow.
186
+ definition.style.top = '';
187
+ definition.style.left = '';
188
+ definition.removeAttribute('relativeX');
189
+ definition.removeAttribute('relativeY');
190
+
181
191
  const term = getTermByDefinition(definition);
182
192
  const termParent = termParentElement(term);
183
193
 
@@ -65,6 +65,12 @@
65
65
  .yfm-code-icon {
66
66
  pointer-events: none;
67
67
  }
68
+
69
+ .yfm-code-prompt {
70
+ color: var(--yfm-color-hljs-comment-private);
71
+ pointer-events: none;
72
+ user-select: none;
73
+ }
68
74
  }
69
75
 
70
76
  &-clipboard-inline-code {
@@ -21,6 +21,14 @@
21
21
  visibility: hidden;
22
22
  opacity: 0;
23
23
 
24
+ // Keep the closed definition off-screen so its (still laid-out) box
25
+ // does not extend the page's scrollable area. Inline top/left set by
26
+ // setDefinitionPosition() are cleared in closeDefinition() to restore
27
+ // these values. Negative-direction overflow does not create a
28
+ // scrollable region, while the box stays measurable for positioning.
29
+ top: -9999px;
30
+ left: -9999px;
31
+
24
32
  padding: 10px;
25
33
 
26
34
  background-color: var(
@@ -3,6 +3,8 @@
3
3
  import type {MarkdownItPluginCb} from './typings';
4
4
  import type {IDGenerator} from './utils';
5
5
 
6
+ import {escapeHtml} from 'markdown-it/lib/common/utils';
7
+
6
8
  import {generateID as globalGenerateID} from './utils';
7
9
 
8
10
  const wrapInFloatingContainer = (
@@ -134,7 +136,57 @@ function balanceSpansPerLine(lines: string[]): string[] {
134
136
  });
135
137
  }
136
138
 
137
- function addLineNumbers(code: string, {lineWrapping}: {lineWrapping: boolean}): string {
139
+ /**
140
+ * Strips the prompt prefix from the raw fence content BEFORE it reaches the highlighter.
141
+ *
142
+ * @param content - Raw fence content.
143
+ * @param prompt - Raw prompt string (e.g. `$`, `#`, `>>>`).
144
+ * @returns Stripped content (same number of lines) and a per-line prompt flag array.
145
+ */
146
+ function stripPrompt(content: string, prompt: string): {content: string; flags: boolean[]} {
147
+ const hasTrailingNewline = content.endsWith('\n');
148
+ const lines = content.split('\n');
149
+ const linesToProcess = hasTrailingNewline ? lines.slice(0, -1) : lines;
150
+
151
+ const flags: boolean[] = [];
152
+ const stripped = linesToProcess.map((line) => {
153
+ const trimmed = line.trimStart();
154
+ const leadingWs = line.slice(0, line.length - trimmed.length);
155
+
156
+ if (trimmed.startsWith(prompt + ' ')) {
157
+ flags.push(true);
158
+ return leadingWs + trimmed.slice(prompt.length + 1);
159
+ }
160
+
161
+ if (trimmed === prompt) {
162
+ flags.push(true);
163
+ return leadingWs;
164
+ }
165
+
166
+ flags.push(false);
167
+ return line;
168
+ });
169
+
170
+ return {
171
+ content: stripped.join('\n') + (hasTrailingNewline ? '\n' : ''),
172
+ flags,
173
+ };
174
+ }
175
+
176
+ function postProcessCode(
177
+ code: string,
178
+ {
179
+ showLineNumbers,
180
+ lineWrapping,
181
+ promptFlags,
182
+ promptEscaped,
183
+ }: {
184
+ showLineNumbers: boolean;
185
+ lineWrapping: boolean;
186
+ promptFlags?: boolean[];
187
+ promptEscaped?: string;
188
+ },
189
+ ): string {
138
190
  const hasTrailingNewline = code.endsWith('\n');
139
191
  const lines = code.split('\n');
140
192
  const linesToProcess = hasTrailingNewline ? lines.slice(0, -1) : lines;
@@ -144,15 +196,53 @@ function addLineNumbers(code: string, {lineWrapping}: {lineWrapping: boolean}):
144
196
  return (
145
197
  normalized
146
198
  .map((line, index) => {
147
- const lineNumber = String(index + 1).padStart(maxDigits, ' ');
148
- return lineWrapping
149
- ? `<span class="yfm-line-number">${lineNumber}</span><span class="yfm-line">${line}</span>`
150
- : `<span class="yfm-line-number">${lineNumber}</span>${line}`;
199
+ // The prompt was already stripped from the raw content before
200
+ // highlighting, so `line` here is the highlighted command only.
201
+ // Re-insert the prompt as a dedicated, non-selectable span after
202
+ // any leading whitespace. `promptFlags` marks which lines carried
203
+ // a prompt in the original source.
204
+ if (promptFlags?.[index] && promptEscaped !== undefined) {
205
+ const trimmed = line.trimStart();
206
+ const leadingWs = line.slice(0, line.length - trimmed.length);
207
+ line =
208
+ `${leadingWs}` +
209
+ `<span class="yfm-code-prompt" aria-hidden="true">${promptEscaped} </span>` +
210
+ `${trimmed}`;
211
+ }
212
+
213
+ if (showLineNumbers) {
214
+ const lineNumber = String(index + 1).padStart(maxDigits, ' ');
215
+ line = lineWrapping
216
+ ? `<span class="yfm-line-number">${lineNumber}</span><span class="yfm-line">${line}</span>`
217
+ : `<span class="yfm-line-number">${lineNumber}</span>${line}`;
218
+ }
219
+
220
+ return line;
151
221
  })
152
222
  .join('\n') + (hasTrailingNewline ? '\n' : '')
153
223
  );
154
224
  }
155
225
 
226
+ /**
227
+ * @param info - Raw fence info string (e.g. `js showLineNumbers prompt="$"`).
228
+ * @returns Parsed flags and the optional prompt value.
229
+ */
230
+ function parseFenceInfo(info: string): {
231
+ showLineNumbers: boolean;
232
+ wrapLines: boolean;
233
+ prompt?: string;
234
+ } {
235
+ const promptMatch = /(?:^|\s)prompt=(?:"([^"]*)"|'([^']*)')/.exec(info);
236
+ const prompt = promptMatch?.[1] ?? promptMatch?.[2];
237
+ const rest = promptMatch ? info.replace(promptMatch[0], ' ') : info;
238
+
239
+ return {
240
+ showLineNumbers: /\bshowLineNumbers\b/.test(rest),
241
+ wrapLines: /\bwrap\b/.test(rest),
242
+ prompt,
243
+ };
244
+ }
245
+
156
246
  type CodeOptions = {
157
247
  /**
158
248
  * Show button to toggle line wrapping of code.
@@ -164,36 +254,69 @@ type CodeOptions = {
164
254
 
165
255
  const code: MarkdownItPluginCb<CodeOptions> = (md, opts) => {
166
256
  const lineWrapping = opts?.codeLineWrapping || false;
167
- const generateID = opts.generateID ?? globalGenerateID;
257
+ const generateID = opts?.generateID ?? globalGenerateID;
168
258
 
169
259
  const superCodeRenderer = md.renderer.rules.fence;
170
260
  md.renderer.rules.fence = function (tokens, idx, options, env, self) {
171
261
  const token = tokens[idx];
172
- const showLineNumbers = token.info.includes('showLineNumbers');
173
- const wrapLines = token.info.includes('wrap');
174
-
262
+ const {showLineNumbers, prompt, wrapLines} = parseFenceInfo(token.info);
175
263
  const shouldWrap = wrapLines;
176
264
 
265
+ // Strip the prompt prefix from the raw content BEFORE handing it
266
+ // to the highlighter, so language grammars never misinterpret prompt
267
+ // symbols (e.g. `#` as a shell comment, `$` as a variable). The prompt is
268
+ // re-inserted as a span in postProcessCode, driven by `promptFlags`.
269
+ let promptFlags: boolean[] | undefined;
270
+ let promptEscaped: string | undefined;
271
+ const originalContent = token.content;
272
+ if (prompt) {
273
+ const stripped = stripPrompt(token.content, prompt);
274
+ token.content = stripped.content;
275
+ promptFlags = stripped.flags;
276
+ promptEscaped = escapeHtml(prompt);
277
+ }
278
+
177
279
  let superCode = superCodeRenderer?.(tokens, idx, options, env, self);
178
280
 
179
- if (superCode && showLineNumbers) {
281
+ // Restore the original content so the mutation does not leak to other
282
+ // consumers of the token.
283
+ token.content = originalContent;
284
+
285
+ if (superCode && (showLineNumbers || prompt)) {
180
286
  // Extract the code content from the pre/code tags
181
287
  const codeMatch = superCode.match(/<pre[^>]*><code[^>]*>([\s\S]*?)<\/code><\/pre>/);
182
288
  if (codeMatch) {
183
289
  const codeContent = codeMatch[1];
184
- const codeWithLineNumbers = addLineNumbers(codeContent, {lineWrapping});
290
+ const processedCode = postProcessCode(codeContent, {
291
+ showLineNumbers,
292
+ lineWrapping,
293
+ promptFlags,
294
+ promptEscaped,
295
+ });
185
296
  // Escape $ in replacement string: $$ becomes a literal $ in String.replace()
186
- const escapedReplacement = codeWithLineNumbers.replace(/\$/g, '$$$$');
297
+ const escapedReplacement = processedCode.replace(/\$/g, '$$$$');
187
298
  superCode = superCode.replace(codeContent, escapedReplacement);
188
299
  }
189
300
  }
190
301
 
191
- if (superCode && shouldWrap) {
192
- superCode = superCode.replace(/<code([^>]*)>/, (_match, attrs) => {
193
- if (attrs.includes('class=')) {
194
- return `<code${attrs.replace(/class="([^"]*)"/, 'class="$1 wrap"')}>`;
302
+ // Attach the raw prompt value as a data attribute on <code> so that the
303
+ // copy widget can strip it from the plain-text content without relying on
304
+ // any class names or DOM structure introduced by the plugin.
305
+ if (superCode && (prompt || shouldWrap)) {
306
+ superCode = superCode.replace(/(<pre[^>]*><code)([^>]*)>/, (_match, open, attrs) => {
307
+ // Add the wrap class
308
+ if (shouldWrap) {
309
+ attrs = /class="[^"]*"/.test(attrs)
310
+ ? attrs.replace(/class="([^"]*)"/, 'class="$1 wrap"')
311
+ : ` class="wrap"${attrs}`;
312
+ }
313
+
314
+ // Add the data-prompt attribute
315
+ if (prompt) {
316
+ attrs = ` data-prompt="${escapeHtml(prompt)}"${attrs}`;
195
317
  }
196
- return `<code class="wrap"${attrs}>`;
318
+
319
+ return `${open}${attrs}>`;
197
320
  });
198
321
  }
199
322
 
@@ -1,5 +1,5 @@
1
1
  import type Token from 'markdown-it/lib/token';
2
- import type {Logger} from 'src/transform/log';
2
+ import type {Logger} from '../../log';
3
3
  import type {CacheContext, StateCore} from '../../typings';
4
4
  import type {MarkdownItPluginCb, MarkdownItPluginOpts} from '../typings';
5
5
  import type {MarkdownItIncluded} from '../includes/types';
@@ -3,7 +3,10 @@ import type Token from 'markdown-it/lib/token';
3
3
  import {formatHref, parseHref} from '@diplodoc/utils';
4
4
 
5
5
  export function isLocalUrl(url: string) {
6
- return !/^(?:[a-z]+:)?\/\//i.test(url);
6
+ // A URL is local unless it has an external scheme: either `scheme://...`
7
+ // / `//host...` (protocol-relative), or an opaque scheme URI without
8
+ // a slash-slash part (e.g. `mailto:`, `tel:`, `custom:`).
9
+ return !isExternalHref(url);
7
10
  }
8
11
 
9
12
  export function findBlockTokens(tokens: Token[], id: string) {