UNPKG

sassdoc-theme-herman

Version:
190 lines (184 loc) 6.73 kB
'use strict'; const path = require('path'); const unixify = require('unixify'); const fontUtils = require('./fonts'); const getFormats = (fmts, src_path) => { const validFormats = {}; let formats = fmts; if (typeof formats === 'string') { formats = [formats]; } for (const format of formats) { if (fontUtils.isValidFormat(format)) { let src = src_path; let dest = src_path; if (src && !src.startsWith('data:')) { dest = `assets/fonts/${unixify(src)}.${format}`; src = path.normalize(`${src}.${format}`); } // Store format type and src/dest paths to file // For embedded fonts (e.g. `data:...`) the dest path will equal src. validFormats[format] = { src, dest }; } } return validFormats; }; module.exports = { sassJson: (contents) => { // Parse the contents of a file containing SassJSON output and return the // first SassJSON line found as a JS object. const startMarker = '/*! json-encode:'; const endMarker = '*/'; const start = contents.indexOf(startMarker); const end = contents.indexOf(endMarker, start); const jsondata = contents.slice(start + startMarker.length, end); return JSON.parse(jsondata); }, font: (font, data) => { // Parse a local font object (key, variants) and return a list of variants, // each with a parsed font ctx (family, formats with filepaths, svgid, // style, weight, and list of `local` keys). const resp = []; const variants = font.variants && font.variants.length ? font.variants : Object.keys(data); for (const variant of variants) { let isLocal = false; let hasEmbedded = false; const isValid = fontUtils.isValidVariant(variant); if (isValid) { const family = data.name || font.key; let svgid = family; // Set weight and style from variant key let weight = 'normal'; let style = 'normal'; for (const variantBit of variant.split(' ')) { if (fontUtils.constants.weight.has(variantBit)) { weight = fontUtils.mapWeight(variantBit); } if (fontUtils.constants.style.has(variantBit)) { style = variantBit; } } let formats = {}; let local; const variantKeys = [ variant, variant.split(' ').join(', '), variant.split(' ').join(','), ]; const variantData = data[variantKeys[0]] || data[variantKeys[1]] || data[variantKeys[2]]; if (variantData) { // Local or embedded font isLocal = true; // Get base path to variant font files const src_path = typeof variantData === 'string' ? variantData : variantData.path; if (data.formats) { formats = getFormats(data.formats, src_path); } if (typeof variantData !== 'string') { // Set variant-specific `local` setting if (variantData.local) { local = typeof variantData.local === 'string' ? [variantData.local] : variantData.local; } // Set variant-specific `svgid` setting if (variantData.svgid) { svgid = variantData.svgid; } for (const key of Object.keys(variantData)) { // For each format specified, store format type and filepath if (fontUtils.isValidFormat(key)) { let src = variantData[key]; let dest = src; if (src.startsWith('data:')) { hasEmbedded = true; } else { dest = `assets/fonts/${unixify(src)}.${key}`; src = path.normalize(`${src}.${key}`); } formats[key] = { src, dest }; } } } } if (!isLocal || local || Object.keys(formats).length) { const ctx = { isLocal, hasEmbedded, variant, family, formats, svgid, style, weight, local, }; resp.push(ctx); } } } return resp; }, customCSS: (file, enc, env) => { // Parse the contents of a file containing CSS output. For any occurrences // of `url(...)` with relative paths, store the paths (for later copying) // and replace them with the eventual destination paths. env.customCSSFiles = env.customCSSFiles || []; let css = file.contents.toString(enc); const regex = /url\((["']?)(?:(?=(\\?))\2.)*?\1\)/g; const matches = []; let nextMatch = regex.exec(css); while (nextMatch !== null) { // Store matches in reverse order for easier reverse-traversing of the css // string while replacing paths. matches.unshift({ text: nextMatch[0], index: nextMatch.index, }); nextMatch = regex.exec(css); } for (const match of matches) { // Ignore initial `url(` and final `)` let src_path = match.text.substring(4, match.text.length - 1); let start_index = match.index + 4; // Ignore quotes, if content is quoted if (src_path.startsWith("'") || src_path.startsWith('"')) { src_path = src_path.substring(1, src_path.length - 1); start_index = start_index + 1; } const doNotRewrite = /^(?:https?:|data:|\/)/i; if (!doNotRewrite.test(src_path)) { const src_dir = path.parse(file.path).dir; const abs_path = path.posix.resolve( unixify(src_dir), unixify(src_path), ); let new_path; if (env.localFonts && env.localFonts.includes(path.resolve(abs_path))) { // This is a font which has already been included with the `@font` // annotation, so point toward that location and do not copy again. const baseFontPath = `${path.resolve(env.dir, env.herman.fontPath)}${ path.sep }`; const rel_path = abs_path.substring( unixify(baseFontPath, false).length, ); new_path = `../fonts/${rel_path}`; } else { const rel_path = path.posix.relative(unixify(env.dir), abs_path); new_path = `./${rel_path}`; // Store reference to original path for later copying of assets env.customCSSFiles.push(path.resolve(abs_path)); } const pre = css.substring(0, start_index); const post = css.substring(start_index + src_path.length); css = pre + new_path + post; } } file.contents = Buffer.from(css); }, };