File: css_decls_font.go

package info (click to toggle)
golang-github-evanw-esbuild 0.25.10-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 10,184 kB
  • sloc: javascript: 28,602; makefile: 856; sh: 17
file content (138 lines) | stat: -rw-r--r-- 3,792 bytes parent folder | download | duplicates (2)
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
package css_parser

import (
	"strconv"
	"strings"

	"github.com/evanw/esbuild/internal/css_ast"
	"github.com/evanw/esbuild/internal/css_lexer"
)

// Specification: https://drafts.csswg.org/css-fonts/#font-prop
// [ <font-style> || <font-variant-css2> || <font-weight> || <font-stretch-css3> ]? <font-size> [ / <line-height> ]? <font-family>
func (p *parser) mangleFont(tokens []css_ast.Token) []css_ast.Token {
	var result []css_ast.Token

	// Scan up to the font size
	pos := 0
	for ; pos < len(tokens); pos++ {
		token := tokens[pos]
		if isFontSize(token) {
			break
		}

		switch token.Kind {
		case css_lexer.TIdent:
			switch strings.ToLower(token.Text) {
			case "normal":
				// "All subproperties of the font property are first reset to their initial values"
				// This implies that "normal" doesn't do anything. Also all of the optional values
				// contain "normal" as an option and they are unordered so it's impossible to say
				// what property "normal" corresponds to. Just drop these tokens to save space.
				continue

			// <font-style>
			case "italic":
			case "oblique":
				if pos+1 < len(tokens) && tokens[pos+1].IsAngle() {
					result = append(result, token, tokens[pos+1])
					pos++
					continue
				}

			// <font-variant-css2>
			case "small-caps":

			// <font-weight>
			case "bold", "bolder", "lighter":
				result = append(result, p.mangleFontWeight(token))
				continue

			// <font-stretch-css3>
			case "ultra-condensed", "extra-condensed", "condensed", "semi-condensed",
				"semi-expanded", "expanded", "extra-expanded", "ultra-expanded":

			default:
				// All other tokens are unrecognized, so we bail if we hit one
				return tokens
			}
			result = append(result, token)

		case css_lexer.TNumber:
			// "Only values greater than or equal to 1, and less than or equal to
			// 1000, are valid, and all other values are invalid."
			if value, err := strconv.ParseFloat(token.Text, 64); err != nil || value < 1 || value > 1000 {
				return tokens
			}
			result = append(result, token)

		default:
			// All other tokens are unrecognized, so we bail if we hit one
			return tokens
		}
	}

	// <font-size>
	if pos == len(tokens) {
		return tokens
	}
	result = append(result, tokens[pos])
	pos++

	// / <line-height>
	if pos < len(tokens) && tokens[pos].Kind == css_lexer.TDelimSlash {
		if pos+1 == len(tokens) {
			return tokens
		}
		result = append(result, tokens[pos], tokens[pos+1])
		pos += 2

		// Remove the whitespace around the "/" character
		if p.options.minifyWhitespace {
			result[len(result)-3].Whitespace &= ^css_ast.WhitespaceAfter
			result[len(result)-2].Whitespace = 0
			result[len(result)-1].Whitespace &= ^css_ast.WhitespaceBefore
		}
	}

	// <font-family>
	if family, ok := p.mangleFontFamily(tokens[pos:]); ok {
		if len(result) > 0 && len(family) > 0 && family[0].Kind != css_lexer.TString {
			family[0].Whitespace |= css_ast.WhitespaceBefore
		}
		return append(result, family...)
	}
	return tokens
}

var fontSizeKeywords = map[string]bool{
	// <absolute-size>: https://drafts.csswg.org/css-fonts/#valdef-font-size-absolute-size
	"xx-small":  true,
	"x-small":   true,
	"small":     true,
	"medium":    true,
	"large":     true,
	"x-large":   true,
	"xx-large":  true,
	"xxx-large": true,

	// <relative-size>: https://drafts.csswg.org/css-fonts/#valdef-font-size-relative-size
	"larger":  true,
	"smaller": true,
}

// Specification: https://drafts.csswg.org/css-fonts/#font-size-prop
func isFontSize(token css_ast.Token) bool {
	// <length-percentage>
	if token.Kind == css_lexer.TDimension || token.Kind == css_lexer.TPercentage {
		return true
	}

	// <absolute-size> or <relative-size>
	if token.Kind == css_lexer.TIdent {
		_, ok := fontSizeKeywords[strings.ToLower(token.Text)]
		return ok
	}

	return false
}