UNPKG

@diplodoc/transform

Version:

A simple transformer of text in YFM (Yandex Flavored Markdown) to HTML

155 lines 6.37 kB
"use strict"; const path_1 = require("path"); const chalk_1 = require("chalk"); const svgo_1 = require("svgo"); const fs_1 = require("fs"); const utilsFS_1 = require("../../utilsFS"); const utils_1 = require("../../utils"); const sanitizeAttribute = (value) => value.replace(/(\d*[%a-z]{0,5}).*/gi, '$1'); function replaceImageSrc(state, currentPath, path, imgSrc, { assetsPublicPath = path_1.sep, root = '', log }) { var _a; if ((0, utilsFS_1.isFileExists)(path)) { (_a = state.md.assets) === null || _a === void 0 ? void 0 : _a.push(imgSrc); } else { log.error(`Asset not found: ${(0, chalk_1.bold)(imgSrc)} in ${(0, chalk_1.bold)(currentPath)}`); } const relativeToRoot = path.replace(root + path_1.sep, ''); const publicSrc = (0, path_1.join)(assetsPublicPath, relativeToRoot); return publicSrc; } function getSvgContent(file, from, { rawContent, notFoundCb, log, root = '' }) { try { return rawContent(file); } catch (e) { const path = file.replace(root, ''); log.error(`SVG ${path} from ${from} not found`); if (notFoundCb) { notFoundCb(path); } return null; } } function shouldBeInlined(token, opts) { var _a; if (!((_a = token.attrGet('src')) === null || _a === void 0 ? void 0 : _a.endsWith('.svg'))) { return false; } const forceInlineSvg = token.attrGet('inline') === 'true'; const shouldInlineSvg = forceInlineSvg || (token.attrGet('inline') !== 'false' && opts.enabled !== false); return shouldInlineSvg; } const getRawFile = (path) => { return (0, fs_1.readFileSync)(path, 'utf8').toString(); }; const index = (md, opts) => { const { rawContent = getRawFile, calcPath = utilsFS_1.resolveRelativePath, replaceImageSrc: replaceImage = replaceImageSrc, } = opts; // TODO:goldserg need remove support opts.inlineSvg if (opts.inlineSvg !== undefined) { opts.svgInline = Object.assign(Object.assign({}, opts.svgInline), { enabled: opts.inlineSvg }); } md.assets = []; const plugin = (state) => { const tokens = state.tokens; (0, utils_1.filterTokens)(tokens, 'inline', (inline, { commented }) => { if (commented || !inline.children) { return; } const childrenTokens = inline.children || []; (0, utils_1.filterTokens)(childrenTokens, 'image', (image, { commented, index }) => { const didPatch = image.attrGet('yfm_patched') || false; if (didPatch || commented) { return; } const imgSrc = (0, utils_1.getSrcTokenAttr)(image); if ((0, utils_1.isExternalHref)(imgSrc)) { return; } const forceInlineSvg = image.attrGet('inline') === 'true'; const shouldInlineSvg = shouldBeInlined(image, opts.svgInline); const imageOpts = { width: image.attrGet('width'), height: image.attrGet('height'), }; const from = state.env.path || opts.path; const file = calcPath(from, imgSrc); if (shouldInlineSvg) { const svgContent = getSvgContent(file, from, Object.assign(Object.assign({}, opts), { rawContent })); if (svgContent) { if (svgContent.length > opts.svgInline.maxFileSize && !forceInlineSvg) { image.attrSet('YFM011', `Svg size: ${svgContent.length}; Config size: ${opts.svgInline.maxFileSize}; Src: ${(0, chalk_1.bold)(file)}`); } else { const svgToken = new state.Token('image_svg', '', 0); svgToken.attrSet('content', replaceSvgContent(svgContent, imageOpts)); childrenTokens[index] = svgToken; } } } if (childrenTokens[index].type === 'image') { image.attrSet('src', replaceImage(state, from, file, imgSrc, opts)); image.attrSet('yfm_patched', '1'); } }); }); }; try { md.core.ruler.before('includes', 'images', plugin); } catch (e) { md.core.ruler.push('images', plugin); } md.renderer.rules.image_svg = (tokens, index) => { const token = tokens[index]; return token.attrGet('content') || ''; }; }; function replaceSvgContent(content, options) { var _a; if (!content) { return ''; } // monoline content = content.replace(/>\r?\n</g, '><').replace(/\r?\n/g, ' '); // remove <?xml...?> content = content.replace(/<\?xml.*?\?>.*?(<svg.*)/g, '$1'); // width, height let svgRoot = content.replace(/.*?<svg([^>]*)>.*/g, '$1'); const { width, height } = ((_a = svgRoot .match(/(?:width="(.*?)")|(?:height="(.*?)")/g)) === null || _a === void 0 ? void 0 : _a.reduce((acc, val) => { const [key, value] = val.split('='); acc[key] = value; return acc; }, {})) || { width: undefined, height: undefined }; if (!width && options.width) { const sanitizedWidth = sanitizeAttribute(options.width.toString()); svgRoot = `${svgRoot} width="${sanitizedWidth}"`; } if (!height && options.height) { const sanitizedHeight = sanitizeAttribute(options.height.toString()); svgRoot = `${svgRoot} height="${sanitizedHeight}"`; } if ((!width && options.width) || (!height && options.height)) { content = content.replace(/.*?<svg([^>]*)>/, `<svg${svgRoot}>`); } // randomize ids content = (0, svgo_1.optimize)(content, { plugins: [ { name: 'prefixIds', params: { prefix: 'rnd-' + Math.floor(Math.random() * 1e9).toString(16), prefixClassNames: false, }, }, ], }).data; return content; } // Create an object that is the index function with an additional replaceSvgContent property const imagesPlugin = Object.assign(index, { replaceSvgContent, }); module.exports = imagesPlugin; //# sourceMappingURL=index.js.map