@diplodoc/transform
Version:
A simple transformer of text in YFM (Yandex Flavored Markdown) to HTML
189 lines • 7.68 kB
JavaScript
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
const url_1 = __importDefault(require("url"));
const chalk_1 = require("chalk");
const path_1 = __importStar(require("path"));
const utils_1 = require("../../utils");
const utilsFS_1 = require("../../utilsFS");
function getTitleFromTokens(tokens) {
var _a;
let title = '';
let i = 0;
while (i < tokens.length) {
const token = tokens[i];
if ((token === null || token === void 0 ? void 0 : token.type) === 'heading_open') {
const info = (0, utils_1.headingInfo)(tokens, i);
title = (_a = info === null || info === void 0 ? void 0 : info.title) !== null && _a !== void 0 ? _a : '';
break;
}
i += 1;
}
return title;
}
const getTitle = (md, id, options) => {
var _a;
const { file, state, opts } = options;
// Check the existed included store and extract it
const included = (_a = md.included) === null || _a === void 0 ? void 0 : _a[file];
const fileTokens = (0, utilsFS_1.getFileTokens)(file, state, Object.assign(Object.assign({}, opts), { disableLint: true, disableTitleRefSubstitution: true, disableCircularError: true, inheritVars: false }), included);
const sourceTokens = id ? (0, utils_1.findBlockTokens)(fileTokens, id) : fileTokens;
return getTitleFromTokens(sourceTokens);
};
const addTitle = (md, options) => {
var _a;
const { hash, state, isEmptyLink, tokens, idx, nextToken, href, currentPath, log, cache } = options;
const id = hash && hash.slice(1);
const key = [id, path_1.default].join('::');
const title = (_a = cache === null || cache === void 0 ? void 0 : cache.get(key)) !== null && _a !== void 0 ? _a : getTitle(md, id, options);
cache === null || cache === void 0 ? void 0 : cache.set(key, title);
if (title) {
let textToken;
if (isEmptyLink) {
textToken = new state.Token('text', '', 0);
tokens.splice(idx + 1, 0, textToken);
}
else {
textToken = nextToken;
}
textToken.content = title;
}
else {
log.warn(`Title not found: ${(0, chalk_1.bold)(href)} in ${(0, chalk_1.bold)(currentPath)}`);
}
};
function getDefaultPublicPath({ file, path, }, input) {
return (0, path_1.relative)((0, path_1.parse)(path || '').dir, input || file || '');
}
// eslint-disable-next-line complexity
function processLink(md, state, tokens, idx, opts) {
const { path: startPath, root, transformLink, notFoundCb, needSkipLinkFn, log, getPublicPath = getDefaultPublicPath, cache, skipLinkFileCheck = false, } = opts;
const currentPath = state.env.path || startPath;
const linkToken = tokens[idx];
const nextToken = tokens[idx + 1];
const originalHref = (0, utils_1.getHrefTokenAttr)(linkToken);
if (!originalHref) {
log.error(`Empty link in ${(0, chalk_1.bold)(startPath)}`);
return;
}
const { pathname, hash } = url_1.default.parse(originalHref);
let file;
let fileExists;
let isPageFile;
if (!(0, utils_1.isLocalUrl)(originalHref)) {
linkToken.attrSet('target', '_blank');
linkToken.attrSet('rel', 'noreferrer noopener');
return;
}
if (pathname) {
file = (0, path_1.resolve)(path_1.default.parse(currentPath).dir, pathname);
fileExists = skipLinkFileCheck || (0, utilsFS_1.isFileExists)(file);
isPageFile = utils_1.PAGE_LINK_REGEXP.test(pathname);
if (isPageFile && !fileExists) {
let needShowError = true;
if (needSkipLinkFn) {
needShowError = !needSkipLinkFn(originalHref);
}
if (notFoundCb && needShowError) {
notFoundCb(file.replace(root, ''));
}
if (needShowError) {
log.error(`Link is unreachable: ${(0, chalk_1.bold)(originalHref)} in ${(0, chalk_1.bold)(currentPath)}`);
}
}
}
else if (hash) {
file = startPath;
fileExists = true;
isPageFile = true;
}
else {
return;
}
const isEmptyLink = nextToken.type === 'link_close';
const isTitleRefLink = nextToken.type === 'text' && nextToken.content === '{#T}';
if ((isEmptyLink || isTitleRefLink) &&
fileExists &&
isPageFile &&
!state.env.disableTitleRefSubstitution) {
addTitle(md, {
hash,
file,
state,
opts,
isEmptyLink,
tokens,
idx,
nextToken,
href: originalHref,
currentPath,
log,
cache,
});
}
const patchedHref = !(0, path_1.isAbsolute)(originalHref) && !originalHref.includes('//')
? url_1.default.format(Object.assign(Object.assign({}, url_1.default.parse(originalHref)), { pathname: getPublicPath(opts, file) }))
: originalHref;
const linkHrefTransformer = transformLink || utils_1.defaultTransformLink;
linkToken.attrSet('href', linkHrefTransformer(patchedHref));
}
const index = (md, opts) => {
const plugin = (state) => {
var _a, _b;
const tokens = state.tokens;
let i = 0;
while (i < tokens.length) {
if (tokens[i].type === 'inline') {
const childrenTokens = tokens[i].children || [];
let j = 0;
while (j < childrenTokens.length) {
const token = childrenTokens[j];
const isLinkOpenToken = token.type === 'link_open';
const tokenClass = token.attrGet('class');
/* Don't process anchor links */
const isYfmAnchor = tokenClass ? tokenClass.includes('yfm-anchor') : false;
const wasProcessedBefore = Boolean((_a = token.meta) === null || _a === void 0 ? void 0 : _a.yfmLinkPluginProcessed);
if (isLinkOpenToken && !wasProcessedBefore && !isYfmAnchor) {
processLink(md, state, childrenTokens, j, opts);
(_b = token.meta) !== null && _b !== void 0 ? _b : (token.meta = {});
token.meta.yfmLinkPluginProcessed = true;
}
j++;
}
}
i++;
}
};
try {
md.core.ruler.before('includes', 'links', plugin);
}
catch (e) {
md.core.ruler.push('links', plugin);
}
};
module.exports = index;
//# sourceMappingURL=index.js.map
;