Skip to content

Commit 03be02f

Browse files
committed
checkpoint
1 parent c632fff commit 03be02f

32 files changed

+10932
-7988
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"check-types": "tsc --noEmit",
2323
"lint-staged": "lint-staged",
2424
"security": "npm audit --audit-level=high --prod",
25-
"test": "ava test/walker.ts"
25+
"test": "ava test/word.ts"
2626
},
2727
"files": [
2828
"dist",

src/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,18 @@
1515
// - Node interfaces changed
1616
// - Walkers must be manually registered to avoid conflicts between different installed versions of
1717
// postcss
18-
// - `2.` is non-spec and invalid (upstream; supported by css-tree)
18+
// - `2.` is non-spec and invalid (upstream; css-tree)
1919
// - `.2.3rem` Shouldn't Be Compliant(upstream; https://github.com/csstree/csstree/issues/194)
2020
// - modulus operators no longer spec-compliant https://www.w3.org/TR/css3-values/#calc-notation
2121
// - custom variable prefix no longer supported (upstream; css-tree)
2222
// - at-words (@word) aren't spec compliant within css values and have been removed
2323
// - `variables` option has been removed. only the `--` prefix is spec compliant for variables
24-
// - url-modifiers (e.g. functions within url()) aren't supported (upstream; https://github.com/csstree/csstree/issues/197)
24+
// - url-modifiers (e.g. functions within url(), url(var(...))) aren't spec compliant and aren't supported (upstream; https://github.com/csstree/csstree/issues/197)
2525
// - a comma (,) is considered an operator
2626
// - strings (Quoted) which are quoted, but unterminated with an ending matching quote mark no longer throw
2727
// - interpolation had to be removed as it is not spec compliant
28+
// - bare parens have their own node type (upstream; css-tree)
29+
// - comparison operators are not spec compliant and not supported. e.g. `(width < 1px)`, `(width < 1px) and (width < 2px)`
2830

2931
import { parse } from './parser';
3032
import { stringify } from './stringify';

src/nodes/Container.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
Copyright © 2018 Andrew Powell
3+
4+
This Source Code Form is subject to the terms of the Mozilla Public
5+
License, v. 2.0. If a copy of the MPL was not distributed with this
6+
file, You can obtain one at http://mozilla.org/MPL/2.0/.
7+
8+
The above copyright notice and this permission notice shall be
9+
included in all copies or substantial portions of this Source Code Form.
10+
*/
11+
import { Input, Container as PostCssContainer } from 'postcss';
12+
13+
import { stringify } from '../stringify';
14+
15+
import { Node, NodeOptions } from './Node';
16+
17+
export class Container extends PostCssContainer {
18+
public readonly value: string = '';
19+
20+
constructor(options?: NodeOptions) {
21+
super({});
22+
23+
if (!this.nodes) this.nodes = [];
24+
25+
if (!options) return;
26+
27+
const { end, source, start } = options.node.loc as any;
28+
29+
this.source = { end, input: new Input(source), start };
30+
}
31+
32+
// Note: The PostCSS types for .push seem a bit jacked up.
33+
// it incorrectly expects properties for types on Declaration for anything being pushed
34+
add(node: Container | Node) {
35+
return this.push(node as any);
36+
}
37+
38+
toString(stringifier = stringify) {
39+
return super.toString(stringifier || {});
40+
}
41+
}

src/nodes/Func.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
Copyright © 2018 Andrew Powell
3+
4+
This Source Code Form is subject to the terms of the Mozilla Public
5+
License, v. 2.0. If a copy of the MPL was not distributed with this
6+
file, You can obtain one at http://mozilla.org/MPL/2.0/.
7+
8+
The above copyright notice and this permission notice shall be
9+
included in all copies or substantial portions of this Source Code Form.
10+
*/
11+
import { FunctionNode } from 'css-tree';
12+
13+
import { Container } from './Container';
14+
import { NodeOptions } from './Node';
15+
16+
const reColorFunctions = /^(hsla?|hwb|lab|lch|rgba?)$/i;
17+
const reVar = /^var$/i;
18+
19+
export class Func extends Container {
20+
readonly isColor: boolean = false;
21+
readonly isVar: boolean = false;
22+
readonly name: string = '<unknown>';
23+
constructor(options: NodeOptions) {
24+
super(options);
25+
this.name = (options.node as FunctionNode).name;
26+
this.isColor = reColorFunctions.test(this.name);
27+
this.isVar = reVar.test(this.name);
28+
this.type = 'func';
29+
}
30+
}

src/nodes/Node.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export class Node extends PostCssNode {
2121
public readonly value: string = '';
2222

2323
constructor(options?: NodeOptions) {
24-
super(options);
24+
super({});
2525

2626
if (!options) return;
2727

src/nodes/Parens.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
Copyright © 2018 Andrew Powell
3+
4+
This Source Code Form is subject to the terms of the Mozilla Public
5+
License, v. 2.0. If a copy of the MPL was not distributed with this
6+
file, You can obtain one at http://mozilla.org/MPL/2.0/.
7+
8+
The above copyright notice and this permission notice shall be
9+
included in all copies or substantial portions of this Source Code Form.
10+
*/
11+
import { Container } from './Container';
12+
import { NodeOptions } from './Node';
13+
14+
export class Parens extends Container {
15+
constructor(options: NodeOptions) {
16+
super(options);
17+
this.type = 'parens';
18+
}
19+
}

src/nodes/Root.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { stringify } from '../stringify';
1515
import { Node } from './Node';
1616

1717
export class Root extends PostCssRoot {
18+
public readonly value = '';
1819
// Note: The PostCSS types for .push seem a bit jacked up.
1920
// it incorrectly expects properties for types on Declaration for anything being pushed
2021
add(node: Node) {

src/nodes/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
export { Container } from './Container';
2+
export { Func } from './Func';
13
export { Node } from './Node';
24
export { Numeric } from './Numeric';
35
export { Operator } from './Operator';
6+
export { Parens } from './Parens';
47
export { Root } from './Root';
58
export { UnicodeRange } from './UnicodeRange';
69
export { Word } from './Word';

src/parser.ts

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
The above copyright notice and this permission notice shall be
99
included in all copies or substantial portions of this Source Code Form.
1010
*/
11-
import { parse as parseAst, Value } from 'css-tree';
11+
import { parse as parseAst, CssNode, CssNodePlain, List, Value } from 'css-tree';
1212
import { Input } from 'postcss';
1313

1414
import { AstError, ParseError } from './errors';
@@ -28,6 +28,50 @@ export interface InterpolationOptions {
2828
prefix: string;
2929
}
3030

31+
interface MaybeParent {
32+
children: List<CssNode> | CssNodePlain[];
33+
}
34+
35+
const assign = (parent: Nodes.Container, nodes: CssNode[]) => {
36+
for (const node of nodes) {
37+
let newNode: Nodes.Container | Nodes.Node;
38+
39+
switch (node.type) {
40+
case 'Function':
41+
newNode = new Nodes.Func({ node });
42+
break;
43+
case 'Dimension':
44+
case 'Number':
45+
newNode = new Nodes.Numeric({ node });
46+
break;
47+
case 'Operator':
48+
newNode = new Nodes.Operator({ node });
49+
break;
50+
case 'Parentheses':
51+
newNode = new Nodes.Parens({ node });
52+
break;
53+
case 'UnicodeRange':
54+
newNode = new Nodes.UnicodeRange({ node });
55+
break;
56+
default:
57+
newNode = new Nodes.Word({ node });
58+
break;
59+
}
60+
61+
const maybeParent = node as unknown as MaybeParent;
62+
63+
if (maybeParent.children) {
64+
let children: CssNode[];
65+
if (maybeParent.children instanceof List) children = maybeParent.children.toArray();
66+
else ({ children } = maybeParent as any);
67+
68+
assign(newNode as Nodes.Container, children);
69+
}
70+
71+
parent.add(newNode);
72+
}
73+
};
74+
3175
export const parse = (css: string, opts?: ParseOptions) => {
3276
// @ts-ignore
3377
// eslint-disable-next-line
@@ -55,23 +99,7 @@ export const parse = (css: string, opts?: ParseOptions) => {
5599

56100
if (!nodes.length) throw new AstError();
57101

58-
for (const node of nodes) {
59-
switch (node.type) {
60-
case 'Dimension':
61-
case 'Number':
62-
root.add(new Nodes.Numeric({ node }));
63-
break;
64-
case 'Operator':
65-
root.add(new Nodes.Operator({ node }));
66-
break;
67-
case 'UnicodeRange':
68-
root.add(new Nodes.UnicodeRange({ node }));
69-
break;
70-
default:
71-
root.add(new Nodes.Word({ node }));
72-
break;
73-
}
74-
}
102+
assign(root, nodes);
75103

76104
return root;
77105
};

src/stringify.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ export class ValuesStringifier extends Stringifier {
5757
this.basic(node);
5858
}
5959

60+
// FIXME: we need to render parens correctly
61+
parens(node: any) {
62+
this.basic(node);
63+
}
64+
6065
punctuation(node: any) {
6166
this.basic(node);
6267
}

src/walker.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ interface Container {
1616
prototype: any;
1717
}
1818

19-
console.log(Object.values(Nodes));
20-
2119
export const registerWalkers = (container: Container) => {
2220
for (const Constructor of Object.values(Nodes)) {
2321
let walkerName = `walk${Constructor.name}`;

test/fixtures/func.json

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{
2+
"snapshot": [
3+
"url()",
4+
"url() foo bar baz",
5+
"url( /gfx/img/bg.jpg )",
6+
"url( '/gfx/img/bg.jpg' )",
7+
"url( \"/gfx/img/bg.jpg\" )",
8+
"url( 'http://domain.com/gfx/img/bg.jpg' )",
9+
"url( \"http://domain.com/gfx/img/bg.jpg\" )",
10+
"url(http://123.example.com)",
11+
"url(//123.example.com)",
12+
"rgba( 29, 439 , 29 )",
13+
"RGBA( 29, 439 , 29 )",
14+
"RgBa( 29, 439 , 29 )",
15+
"Lab( 40% 56.6 39 )",
16+
"lCH(40% 68.8 34.5 / 50%)",
17+
"hwb(90deg 0% 0% / 0.5)",
18+
"calc(-0.5 * var(foo))",
19+
"calc(var(--foo)*var(--bar))",
20+
"calc(1px + -2vw - 4px)",
21+
"calc(((768px - 100vw) / 2) - 15px)",
22+
"calc(((768px - 100vw)/2) - 15px)",
23+
"bar(baz(black, 10%), 10%)",
24+
"-webkit-linear-gradient(0)",
25+
"var(--foo)",
26+
"var( --foo)",
27+
"var(--foo )",
28+
"var( --foo )",
29+
"var(--foo, default-value)",
30+
"rotate(72.3deg)",
31+
"rotate(0.5deg)",
32+
"rotate(.5deg)",
33+
"rotate(0.5rad)",
34+
"rotate(0.5grad)",
35+
"rotate(0.5turn)",
36+
"1em/var(--line-height)",
37+
"local(foo),local(bar)",
38+
"bat-man(#000)",
39+
"conic-gradient()",
40+
"url( /gfx/img/bg.jpg ",
41+
"src(var(--foo))"
42+
],
43+
"throws": [
44+
"url(var(--foo))",
45+
"url(\"/gfx/img/bg.jpg\" hello )",
46+
"url(\"http://domain.com/gfx/img/bg.jpg\" hello )",
47+
"color.red(#6b717f)"
48+
]
49+
}

test/fixtures/quoted.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"snapshot": [
3+
"\"\"",
4+
"''",
5+
"'word\\'word'",
6+
"\"word\\\\\"word\"",
7+
"\"word\\'word\"",
8+
"'word\"word'",
9+
"\"string\"",
10+
"word1\"string\"word2",
11+
" \"foo\" ",
12+
"\"word",
13+
"\"word\\",
14+
" \\\"word\\'\\ \\\t "
15+
]
16+
}

test/fixtures/walker.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"values": [
3+
{
4+
"value": "calc((foo(768px - 100vw) / 2) - 15px) // batman\n//joker",
5+
"walkers": [
6+
{
7+
"length": 2,
8+
"type": "Funcs"
9+
},
10+
{
11+
"length": 4,
12+
"type": "Numerics"
13+
},
14+
{
15+
"length": 2,
16+
"type": "Words"
17+
}
18+
]
19+
}
20+
]
21+
}

test/fixtures/word.js

Lines changed: 0 additions & 28 deletions
This file was deleted.

test/fixtures/word.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"snapshot": [
3+
"bold italic 12px \t /3 'Open Sans', Arial, \"Helvetica Neue\", sans-serif",
4+
" \\\"word\\\" \\s ",
5+
"--color",
6+
"-webkit-transition",
7+
"#fff",
8+
"#123 #f09f #abcdef #a2b3c4d5",
9+
"blanchedalmond",
10+
"BLANCHEDALMOND",
11+
"blAncHedaLmoNd"
12+
]
13+
}

0 commit comments

Comments
 (0)