Skip to content

Commit 860808b

Browse files
authored
Parser of template placeholder (stylelint#42)
1 parent 2024e1b commit 860808b

16 files changed

+355
-23
lines changed

object-stringifier.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class ObjectStringifier extends Stringifier {
1818
this.builder("}", node, "end");
1919
}
2020
literal (node, semicolon) {
21-
this.builder(node.text + (semicolon ? "," : ""));
21+
this.builder(node.text + (semicolon ? "," : ""), node);
2222
}
2323
decl (node, semicolon) {
2424
let prop = this.rawValue(node, "prop");

template-parser-helper.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"use strict";
2+
const Literal = require("./literal");
3+
const isLiteral = token => token[0] === "word" && /^\$\{.*\}$/.test(token[1]);
4+
function literal (start) {
5+
if (!isLiteral(start)) {
6+
return;
7+
}
8+
const tokens = [];
9+
let hasWord;
10+
let type;
11+
let token;
12+
while ((token = this.tokenizer.nextToken())) {
13+
tokens.push(token);
14+
type = token[0];
15+
if (type.length === 1) {
16+
break;
17+
} else if (type === "word") {
18+
hasWord = true;
19+
}
20+
}
21+
22+
while (tokens.length) {
23+
this.tokenizer.back(tokens.pop());
24+
}
25+
26+
if (type === "{" || (type === ":" && !hasWord)) {
27+
return;
28+
}
29+
30+
const node = new Literal({
31+
text: start[1],
32+
});
33+
34+
this.init(node, start[2], start[3]);
35+
36+
return node;
37+
}
38+
39+
function freeSemicolon (token) {
40+
this.spaces += token[1];
41+
const nodes = this.current.nodes;
42+
const prev = nodes && nodes[nodes.length - 1];
43+
if (prev && /^(rule|literal)$/.test(prev.type) && !prev.raws.ownSemicolon) {
44+
prev.raws.ownSemicolon = this.spaces;
45+
this.spaces = "";
46+
}
47+
}
48+
49+
module.exports = {
50+
freeSemicolon: freeSemicolon,
51+
literal: literal,
52+
};

template-parser.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
"use strict";
22
const Parser = require("postcss/lib/parser");
33
const templateTokenize = require("./template-tokenize");
4+
const helper = require("./template-parser-helper");
5+
46
class TemplateParser extends Parser {
57
createTokenizer () {
68
this.tokenizer = templateTokenize(this.input);
79
}
10+
other () {
11+
const args = arguments;
12+
return helper.literal.apply(this, args) || super.other.apply(this, args);
13+
}
14+
freeSemicolon () {
15+
return helper.freeSemicolon.apply(this, arguments);
16+
}
817
}
918
module.exports = TemplateParser;

template-safe-parser.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
"use strict";
22
const SafeParser = require("postcss-safe-parser/lib/safe-parser");
33
const templateTokenize = require("./template-tokenize");
4+
const helper = require("./template-parser-helper");
5+
46
class TemplateSafeParser extends SafeParser {
57
createTokenizer () {
68
this.tokenizer = templateTokenize(this.input, { ignoreErrors: true });
79
}
10+
other () {
11+
const args = arguments;
12+
return helper.literal.apply(this, args) || super.other.apply(this, args);
13+
}
14+
freeSemicolon () {
15+
return helper.freeSemicolon.apply(this, arguments);
16+
}
817
}
918
module.exports = TemplateSafeParser;

template-stringifier.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
"use strict";
2+
const Stringifier = require("postcss/lib/stringifier");
3+
4+
class TemplateStringifier extends Stringifier {
5+
literal (node) {
6+
this.builder(node.text, node);
7+
if (node.raws.ownSemicolon) {
8+
this.builder(node.raws.ownSemicolon, node, "end");
9+
}
10+
}
11+
};
12+
13+
module.exports = TemplateStringifier;

template-stringify.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"use strict";
2+
const TemplateStringifier = require("./template-stringifier");
3+
4+
module.exports = function TemplateStringify (node, builder) {
5+
const str = new TemplateStringifier(builder);
6+
str.stringify(node);
7+
};

template-tokenize.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,18 @@ function templateTokenize (input) {
3232
returned.push(token);
3333
}
3434
if (returned.length) {
35-
const lastToken = returned[returned.length - 1];
35+
let lastToken = returned[returned.length - 1];
3636
if (token && token !== lastToken) {
37-
back(token);
37+
if (token[0] === returned[0][0]) {
38+
returned.push(token);
39+
lastToken = token;
40+
} else {
41+
back(token);
42+
}
43+
}
44+
while (lastToken[0] === "space") {
45+
back(returned.pop());
46+
lastToken = returned[returned.length - 1];
3847
}
3948
token = [
4049
returned[0][0],
@@ -45,7 +54,6 @@ function templateTokenize (input) {
4554
lastToken[5] || lastToken[3],
4655
];
4756
}
48-
4957
return token;
5058
}
5159
return Object.assign({}, tokenizer, {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import styled, { css } from "styled-components";
2+
3+
export const buttonStyles = css`
4+
display: inline-block;
5+
`;
6+
7+
export const ButtonStyled1 = styled.button`
8+
${buttonStyles}
9+
color: red;
10+
`;
11+
12+
export const ButtonStyled2 = styled.button`
13+
${buttonStyles};
14+
color: red;
15+
`;
16+
17+
export const ButtonStyled3 = styled.button`
18+
;
19+
color: red;
20+
${buttonStyles}
21+
`;
22+
23+
export const ButtonStyled4 = styled.button`
24+
;
25+
color: red;
26+
${buttonStyles};
27+
`;

test/fixtures/multiline-arrow-function.js

Lines changed: 0 additions & 7 deletions
This file was deleted.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import styled from "styled-components";
2+
3+
export const StatusText = styled.div`
4+
color: ${(props) =>
5+
(props.status === "signed" && "red") ||
6+
"blue"};
7+
`;

0 commit comments

Comments
 (0)