Skip to content

Commit 659f5aa

Browse files
author
Robin Frischmann
authored
Merge pull request #8 from rofrischmann/2-expressions
adding support for calc expressions
2 parents d479773 + 15b8c36 commit 659f5aa

File tree

8 files changed

+102
-51
lines changed

8 files changed

+102
-51
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ ast === {
8686
* [Dimension](docs/ASTNodes.md#dimension)
8787
* [Float](docs/ASTNodes.md#float)
8888
* [Function](docs/ASTNodes.md#function)
89+
* [Expression](docs/ASTNodes.md#expression)
8990

9091

9192
## Support

docs/ASTNodes.md

Lines changed: 73 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,15 @@ body: [ /* child nodes */ ]
2121
* [Dimension](#dimension)
2222
* [Float](#float)
2323
* [Function](#function)
24+
* [Expression](#expression)
2425

2526
## Identifier
2627
Identifiers are all kind of words such as `solid`.
2728
```javascript
2829
// e.g. solid
2930
{
30-
type: 'Identifier',
31-
value: 'solid'
31+
type: 'Identifier',
32+
value: 'solid'
3233
}
3334
```
3435

@@ -37,8 +38,8 @@ Integers are simple numbers without a unit or fractional part.
3738
```javascript
3839
// e.g. 34
3940
{
40-
type: 'Integer',
41-
value: 34
41+
type: 'Integer',
42+
value: 34
4243
}
4344
```
4445

@@ -47,8 +48,8 @@ Keywords are special identifier that are globally valid for CSS. These are `inhe
4748
```javascript
4849
// e.g. inherit
4950
{
50-
type: 'Keyword',
51-
value: 'inherit'
51+
type: 'Keyword',
52+
value: 'inherit'
5253
}
5354
```
5455

@@ -58,8 +59,8 @@ Operators are basic arithmetic expression symbols for addition `+`, subtraction
5859
```javascript
5960
// e.g. +
6061
{
61-
type: 'Operator',
62-
value: '+'
62+
type: 'Operator',
63+
value: '+'
6364
}
6465
```
6566

@@ -69,8 +70,8 @@ HexColor represents color values given in hexadecimal notation.
6970
```javascript
7071
// e.g. #FF66FF
7172
{
72-
type: 'HexColor',
73-
value: '#FF66FF'
73+
type: 'HexColor',
74+
value: '#FF66FF'
7475
}
7576
```
7677

@@ -80,8 +81,8 @@ URL is used for any URI-type string. *It is not validated by the parser!*
8081
```javascript
8182
// e.g. https://github.com/
8283
{
83-
type: 'URL',
84-
value: 'https://github.com/'
84+
type: 'URL',
85+
value: 'https://github.com/'
8586
}
8687
```
8788

@@ -91,8 +92,8 @@ Strings are all values that are wrapped in quotes, either single `'` or double `
9192
```javascript
9293
// e.g. "I'm a string!!11!1"
9394
{
94-
type: 'String',
95-
value: 'I\'m a string!!11!1'
95+
type: 'String',
96+
value: 'I\'m a string!!11!1'
9697
}
9798
```
9899

@@ -113,10 +114,10 @@ Dimensions are special integers or floats that are postfixed with an extra unit.
113114
```javascript
114115
// e.g. 12px
115116
{
116-
type: 'Dimension',
117-
value: 12,
118-
unit: 'px',
119-
dimension: 'absolute-length'
117+
type: 'Dimension',
118+
value: 12,
119+
unit: 'px',
120+
dimension: 'absolute-length'
120121
}
121122
```
122123

@@ -132,9 +133,9 @@ Floats are floating-point numbers with a fractional part and an integer part. *(
132133
```javascript
133134
// e.g. 587.923
134135
{
135-
type: 'Float',
136-
integer: 587,
137-
fractional: 923
136+
type: 'Float',
137+
integer: 587,
138+
fractional: 923
138139
}
139140
```
140141

@@ -150,8 +151,56 @@ Functions represent CSS functions wrapped in parentheses.
150151

151152
// e.g. rgba(10, 20, 30, 0.55)
152153
{
153-
type: 'Function',
154-
callee: 'rgba'
155-
params: [ /* param nodes */ ]
154+
type: 'Function',
155+
callee: 'rgba'
156+
params: [{
157+
type: 'Integer',
158+
value: 10
159+
}, {
160+
type: 'Integer',
161+
value: 20
162+
}, {
163+
type: 'Integer',
164+
value: 30
165+
}, {
166+
type: 'Float',
167+
integer: 0,
168+
fractional: 55
169+
}]
170+
}
171+
```
172+
173+
## Expression
174+
Expressions are mathematical calculations. They may only be used inside the CSS `calc`-function.
175+
176+
| Property | Description |
177+
| ------ | ------ |
178+
| body | An array of any AST nodes |
179+
180+
```javascript
181+
182+
// e.g. 100% - 30px*3
183+
{
184+
type: 'Expression',
185+
body: [{
186+
type: 'Dimension',
187+
value: 100,
188+
unit: '%',
189+
dimension: 'percentage'
190+
}, {
191+
type: 'Operator',
192+
value: '-'
193+
}, {
194+
type: 'Dimension',
195+
value: 30,
196+
unit: 'px',
197+
dimension: 'absolute-length'
198+
}, {
199+
type: 'Operator',
200+
value: '*'
201+
}, {
202+
type: 'Integer',
203+
value: 3
204+
}]
156205
}
157206
```

modules/__tests__/tokenizer-test.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,11 +160,8 @@ describe('Tokenizing CSS values', () => {
160160

161161
it('should return an array of tokens', () => {
162162
expect(tokenizeCSSValue('#FF66f6')).toEqual([{
163-
type: 'hash',
164-
value: '#'
165-
}, {
166163
type: 'hexadecimal',
167-
value: 'FF66f6'
164+
value: '#FF66f6'
168165
}])
169166
})
170167
})

modules/generator.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ export default class Generator {
99
case 'CSSValue':
1010
return node.body.map(generateCSSValue).join(' ')
1111

12+
case 'Expression':
13+
return node.body.map(generateCSSValue).join('')
14+
1215
case 'Function':
1316
return `${node.callee}(${node.params.map(generateCSSValue).join(',')})`
1417

@@ -19,9 +22,9 @@ export default class Generator {
1922
return `${node.integer ? node.integer : ''}.${node.fractional}`
2023

2124
case 'Operator':
22-
// we use spacings left and right to ensure
23-
// correct syntax inside calc expressions
24-
return ` ${node.value} `
25+
// for addition and substraction we use spacings left and right
26+
// to ensure correct syntax inside calc expressions
27+
return node.value === '+' || node.value === '-' ? ` ${node.value} ` : node.value
2528

2629
case 'String':
2730
return node.quote + node.value + node.quote

modules/index.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,3 @@ export default function parse(input: string): ParsedCSSValue {
2424
}
2525
}
2626
}
27-
28-
const input = '1px solid "helloMyName\'is\'foo" url(https://www.youtube.com/watch?v=CSvFpBOe8eY'
29-
30-
const parsed = parse(input)
31-
32-
console.log(parsed.toString())

modules/parser.js

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,18 @@ export default class Parser {
100100
return this.parseURL()
101101
}
102102

103+
if (this.currentToken.value.indexOf('calc') > -1) {
104+
const node = this.parseFunction()
105+
106+
const functionParams = node.params
107+
node.params = [{
108+
type: 'Expression',
109+
body: functionParams
110+
}]
111+
112+
return node
113+
}
114+
103115
return this.parseFunction()
104116
}
105117

@@ -247,16 +259,10 @@ export default class Parser {
247259
}
248260

249261
parseHexColor() {
250-
if (this.currentToken.type === 'hash') {
251-
const nextToken = this.getNextToken(1)
252-
253-
if (nextToken.type === 'hexadecimal') {
254-
this.updateCurrentToken(1)
255-
256-
return {
257-
type: 'HexColor',
258-
value: `#${nextToken.value}`
259-
}
262+
if (this.currentToken.type === 'hexadecimal') {
263+
return {
264+
type: 'HexColor',
265+
value: this.currentToken.value
260266
}
261267
}
262268
}
@@ -283,6 +289,7 @@ export default class Parser {
283289
this.parseString()
284290

285291
if (!node) {
292+
console.log(this.currentToken)
286293
throw new SyntaxError(('Cannot parse': node))
287294
}
288295

modules/traverser.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export default class Traverser {
2121

2222
switch (node.type) {
2323
case 'CSSValue':
24+
case 'Expression':
2425
this.traverseNodeList(node.body, node)
2526
break
2627

modules/utils/CSSValueRules.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@ export default {
1515
number: /^\d+$/,
1616
url_chars: /^[&:=?]$/,
1717
floating_point: /^[.]$/,
18-
hexadecimal: /^([0-9a-f]+)$/i,
18+
hexadecimal: /^#([0-9a-f]*)$/i,
1919
whitespace: /^\s+$/,
20-
paren: /^[()]+$/,
21-
comma: /^,+$/,
22-
hash: /^#$/
20+
paren: /^[()]$/,
21+
comma: /^,+$/
2322
}

0 commit comments

Comments
 (0)