UNPKG

@diplodoc/transform

Version:

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

180 lines (151 loc) 4.63 kB
import type {Dictionary} from 'lodash'; import {readFileSync, realpathSync, statSync} from 'fs'; import escapeRegExp from 'lodash/escapeRegExp'; import {join, parse, relative, resolve, sep} from 'path'; import QuickLRU from 'quick-lru'; import liquidSnippet from './liquid'; import {StateCore} from './typings'; import {defaultTransformLink} from './utils'; import {preprocess} from './preprocessors'; const filesCache = new QuickLRU<string, string>({maxSize: 1000}); export function isFileExists(file: string) { try { const stats = statSync(file); return stats.isFile(); } catch (e) { return false; } } export function resolveRelativePath(fromPath: string, relativePath: string) { const {dir: fromDir} = parse(fromPath); return resolve(fromDir, relativePath); } export type GetFileTokensOpts = { getVarsPerFile?: (path: string) => Record<string, string>; vars?: Record<string, unknown>; disableLiquid?: boolean; disableLint?: boolean; lintMarkdown?: (opts: {input: string; path: string; sourceMap?: Dictionary<string>}) => void; disableTitleRefSubstitution?: boolean; disableCircularError?: boolean; inheritVars?: boolean; conditionsInCode?: boolean; content?: string; }; export function getFileTokens( path: string, state: StateCore, options: GetFileTokensOpts, content?: string, ) { const { getVarsPerFile, vars, disableLiquid, disableLint, lintMarkdown, disableTitleRefSubstitution, disableCircularError, inheritVars = true, conditionsInCode, } = options; const builtVars = (getVarsPerFile && !inheritVars ? getVarsPerFile(path) : vars) || {}; // Read the content only if we dont have one in the args if (!content) { if (filesCache.has(path)) { content = filesCache.get(path) as string; } else { content = readFileSync(path, 'utf8'); filesCache.set(path, content); } } let sourceMap; if (!disableLiquid) { const liquidResult = liquidSnippet(content, builtVars, path, { withSourceMap: true, conditionsInCode, }); content = liquidResult.output; sourceMap = liquidResult.sourceMap; } // Run preprocessor content = preprocess(content, options); if (!disableLint && lintMarkdown) { lintMarkdown({ input: content, path, sourceMap, }); } const meta = state.md.meta; const tokens = state.md.parse(content, { ...state.env, path, disableTitleRefSubstitution, disableCircularError, }); state.md.meta = meta; return tokens; } export const getFullIncludePath = (includePath: string, root: string, path: string) => { let fullIncludePath; if (includePath.startsWith(sep)) { fullIncludePath = join(root, includePath); } else { fullIncludePath = resolveRelativePath(path, includePath); } return fullIncludePath; }; export function getSinglePageAnchorId(args: { root: string; currentPath: string; pathname?: string; hash?: string | null; }) { const {root, currentPath, pathname, hash} = args; let resultAnchor = currentPath; if (pathname) { resultAnchor = resolveRelativePath(currentPath, pathname); } resultAnchor = resultAnchor .replace(root, '') .replace(/\.(md|ya?ml|html)$/i, '') .replace(new RegExp(escapeRegExp(sep), 'gi'), '_'); if (hash) { resultAnchor = resultAnchor + '_' + hash.slice(1); } return `#${resultAnchor}`; } export function getPublicPath( { path, root, rootPublicPath, transformLink, }: { path?: string; root?: string; rootPublicPath?: string; transformLink?: (href: string) => string; }, input?: string | null, ) { const currentPath = input || path || ''; const filePath = relative(resolve(root || '', rootPublicPath || ''), currentPath); const transformer = transformLink || defaultTransformLink; const href = transformer(filePath); return href; } export function getRelativePath(path: string, toPath: string) { const pathDirs = path.split(sep); pathDirs.pop(); const parentPath = pathDirs.join(sep); return relative(parentPath, toPath); } export function getRealPath(symlinkPath: string): string { try { return realpathSync(symlinkPath); } catch (err) { return symlinkPath; } }