@diplodoc/transform 4.77.9 → 4.77.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diplodoc/transform",
3
- "version": "4.77.9",
3
+ "version": "4.77.10",
4
4
  "description": "A simple transformer of text in YFM (Yandex Flavored Markdown) to HTML",
5
5
  "keywords": [
6
6
  "markdown",
@@ -115,19 +115,76 @@ function isGalleryValid(value: string): boolean {
115
115
  return value === 'true' || value === 'false';
116
116
  }
117
117
 
118
- function collectDataAttrs(image: Token): Record<string, string> {
118
+ function resolveGallerySrcAttr(
119
+ key: string,
120
+ value: string,
121
+ state: StateCore,
122
+ from: string,
123
+ calcPath: (root: string, path: string) => string,
124
+ replaceImage: typeof replaceImageSrc,
125
+ opts: ImageOpts,
126
+ ): [string, string] | null {
127
+ if (key !== 'gallery-src' && key !== 'data-gallery-src') {
128
+ return null;
129
+ }
130
+
131
+ if (!value) {
132
+ return null;
133
+ }
134
+
135
+ const galleryFile = calcPath(from, value);
136
+ const processedSrc = replaceImage(state, from, galleryFile, value, opts);
137
+
138
+ return ['data-gallery-src', processedSrc];
139
+ }
140
+
141
+ function collectDataAttrs(
142
+ image: Token,
143
+ state: StateCore,
144
+ from: string,
145
+ calcPath: (root: string, path: string) => string,
146
+ replaceImage: typeof replaceImageSrc,
147
+ opts: ImageOpts,
148
+ ): Record<string, string> {
119
149
  const result: Record<string, string> = {};
120
150
  if (!image.attrs) return result;
121
151
 
122
152
  for (const [key, value] of image.attrs) {
123
153
  if (key === 'gallery' && isGalleryValid(value)) {
124
154
  result['data-gallery'] = value;
125
- } else if (key.startsWith('data-') && (key !== 'data-gallery' || isGalleryValid(value))) {
155
+ continue;
156
+ }
157
+
158
+ const gallerySrc = resolveGallerySrcAttr(
159
+ key,
160
+ value,
161
+ state,
162
+ from,
163
+ calcPath,
164
+ replaceImage,
165
+ opts,
166
+ );
167
+
168
+ if (gallerySrc) {
169
+ result[gallerySrc[0]] = gallerySrc[1];
170
+ continue;
171
+ }
172
+
173
+ if (
174
+ key.startsWith('data-') &&
175
+ key !== 'data-gallery-src' &&
176
+ (key !== 'data-gallery' || isGalleryValid(value))
177
+ ) {
126
178
  result[key] = value;
127
179
  }
128
180
  }
181
+
129
182
  image.attrs = image.attrs.filter(
130
- ([key, value]) => key !== 'gallery' && (key !== 'data-gallery' || isGalleryValid(value)),
183
+ ([key, value]) =>
184
+ key !== 'gallery' &&
185
+ key !== 'gallery-src' &&
186
+ (key !== 'data-gallery' || isGalleryValid(value)) &&
187
+ (key !== 'data-gallery-src' || value !== ''),
131
188
  );
132
189
  return result;
133
190
  }
@@ -162,7 +219,8 @@ const index: MarkdownItPluginCb<Opts> = (md, opts) => {
162
219
  const imgSrc = getSrcTokenAttr(image);
163
220
  if (isExternalHref(imgSrc)) return;
164
221
 
165
- const dataAttrs = collectDataAttrs(image);
222
+ const from = state.env.path || opts.path;
223
+ const dataAttrs = collectDataAttrs(image, state, from, calcPath, replaceImage, opts);
166
224
  const forceInlineSvg = image.attrGet('inline') === 'true';
167
225
  const imageOpts = {
168
226
  width: image.attrGet('width'),
@@ -171,7 +229,6 @@ const index: MarkdownItPluginCb<Opts> = (md, opts) => {
171
229
  dataAttrs,
172
230
  };
173
231
 
174
- const from = state.env.path || opts.path;
175
232
  const file = calcPath(from, imgSrc);
176
233
 
177
234
  if (shouldBeInlined(image, opts.svgInline)) {
@@ -225,6 +282,18 @@ const index: MarkdownItPluginCb<Opts> = (md, opts) => {
225
282
  };
226
283
  };
227
284
 
285
+ function applyDataAttrs(svgRoot: string, dataAttrs: Record<string, string>): string {
286
+ let result = svgRoot;
287
+
288
+ for (const [key, value] of Object.entries(dataAttrs)) {
289
+ if (!result.includes(`${key}=`)) {
290
+ result = `${result} ${key}="${sanitizeHTMLAttr(value)}"`;
291
+ }
292
+ }
293
+
294
+ return result;
295
+ }
296
+
228
297
  function replaceSvgContent(
229
298
  content: string | null,
230
299
  options: ImageOptions,
@@ -263,9 +332,7 @@ function replaceSvgContent(
263
332
  }
264
333
 
265
334
  if (options.dataAttrs) {
266
- for (const [key, value] of Object.entries(options.dataAttrs)) {
267
- svgRoot = `${svgRoot} ${key}="${sanitizeHTMLAttr(value)}"`;
268
- }
335
+ svgRoot = applyDataAttrs(svgRoot, options.dataAttrs);
269
336
  content = content.replace(/<svg([^>]*)>/, `<svg${svgRoot}>`);
270
337
  }
271
338
 
@@ -294,8 +294,10 @@ type ParsedAttrs = {
294
294
 
295
295
  function resolveDataAttr(key: string, value: string): [string, string] | null {
296
296
  const isGalleryValid = value === 'true' || value === 'false';
297
+
297
298
  if (key === 'gallery') return isGalleryValid ? ['data-gallery', value] : null;
298
299
  if (key === 'data-gallery') return isGalleryValid ? [key, value] : null;
300
+ if (key === 'gallery-src') return value !== '' ? ['data-gallery-src', value] : null;
299
301
  if (key.startsWith('data-')) return [key, value];
300
302
  return null;
301
303
  }