All files index.ts

100% Statements 65/65
100% Branches 38/38
100% Functions 7/7
100% Lines 62/62
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 1471x 1x 1x 1x 1x 1x 1x                               1x   1x             1x 50x 1x     49x 1x     48x 6x     42x               42x 42x 42x         85x 3x     260x 260x 41x       38x 38x 38x 8x 30x 1x 1x   38x 1x   37x   148x 148x     37x     1x     82x 75x   7x 1x   6x       75x 58x   17x 1x   16x       58x 45x   13x 1x   12x       45x                 13x   7x       9x 9x 5x   4x       1x  
const unquote = require('unquote')
const systemFontKeywords = require('css-system-font-keywords')
const fontWeightKeywords = require('css-font-weight-keywords')
const fontStyleKeywords = require('css-font-style-keywords')
const fontStretchKeywords = require('css-font-stretch-keywords')
import * as cssListHelpers from 'css-list-helpers'
import * as helpers from './helpers'
 
export interface ISystemFont {
	system: string
}
 
export interface IFont {
	style?: string
	variant?: string
	weight?: string
	stretch?: string
	size?: string
	lineHeight?: string | number
	family?: string[]
}
 
const errorPrefix = '[parse-css-font]'
 
const firstDeclarations: ['style', 'weight', 'stretch', 'variant'] = [
	'style',
	'weight',
	'stretch',
	'variant',
]
 
export default function parseCSSFont(value: string) {
	if (typeof value !== 'string') {
		throw error('Expected a string.', TypeError)
	}
 
	if (value === '') {
		throw error('Cannot parse an empty string.')
	}
 
	if (systemFontKeywords.indexOf(value) !== -1) {
		return { system: value } as ISystemFont
	}
 
	const font: IFont = {
		lineHeight: 'normal',
		stretch: '',
		style: '',
		variant: '',
		weight: '',
	}
 
	const consumers = [style, weight, stretch, variant]
	const tokens = cssListHelpers.splitBySpaces(value)
	nextToken: for (
		let token = tokens.shift();
		!!token;
		token = tokens.shift()
	) {
		if (token === 'normal') {
			continue
		}
 
		for (const consume of consumers) {
			if (consume(token)) {
				continue nextToken
			}
		}
 
		const parts = cssListHelpers.split(token, ['/'])
		font.size = parts[0]
		if (!!parts[1]) {
			font.lineHeight = parseLineHeight(parts[1])
		} else if (tokens[0] === '/') {
			tokens.shift()
			font.lineHeight = parseLineHeight(tokens.shift() as string)
		}
		if (!tokens.length) {
			throw error('Missing required font-family.')
		}
		font.family = cssListHelpers.splitByCommas(tokens.join(' ')).map(unquote)
 
		for (const name of firstDeclarations) {
			font[name] = font[name] || 'normal'
		}
 
		return font
	}
 
	throw error('Missing required font-size.')
 
	function style(token: string) {
		if (fontStyleKeywords.indexOf(token) === -1) {
			return
		}
		if (font.style) {
			throw error('Font style already defined.')
		}
		return (font.style = token)
	}
 
	function weight(token: string) {
		if (fontWeightKeywords.indexOf(token) === -1) {
			return
		}
		if (font.weight) {
			throw error('Font weight already defined.')
		}
		return (font.weight = token)
	}
 
	function stretch(token: string) {
		if (fontStretchKeywords.indexOf(token) === -1) {
			return
		}
		if (font.stretch) {
			throw error('Font stretch already defined.')
		}
		return (font.stretch = token)
	}
 
	function variant(token: string) {
		return (
			!helpers.isSize(token) &&
			(font.variant = font.variant ? [font.variant, token].join(' ') : token)
		)
	}
}
 
function error(
	message: string,
	ErrorType: typeof Error | typeof TypeError = Error,
) {
	return new ErrorType(`${errorPrefix} ${message}`)
}
 
function parseLineHeight(value: string) {
	const parsed = parseFloat(value)
	if (parsed.toString() === value) {
		return parsed
	}
	return value
}
 
// @ts-ignore
module.exports = Object.assign(exports.default, exports)