Skip to content

Commit 5e6433d

Browse files
e-cloudshellscape
authored andcommitted
fix: handle whitespace between variable and colon (#101)
the variable declaration in less is somehow similar to at rule in css, makes its detection more complicated.
1 parent d1b44b8 commit 5e6433d

File tree

3 files changed

+76
-32
lines changed

3 files changed

+76
-32
lines changed

lib/tokenizer/globals.js

+2
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,7 @@ export const atEndPattern = /[ \n\t\r\f\{\(\)'"\\;/\[\]#]/g;
2828
export const wordEndPattern = /[ \n\t\r\f\(\)\{\}:,;@!'"\\\]\[#]|\/(?=\*)/g;
2929
export const badBracketPattern = /.[\\\/\("'\n]/;
3030

31+
export const pageSelectorPattern = /^@page[^\w-]+/;
32+
export const variableSpaceColonPattern = /^\s*:/;
3133
export const variablePattern = /^@[^:\(\{]+:/;
3234
export const hashColorPattern = /^#[0-9a-fA-F]{6}$|^#[0-9a-fA-F]{3}$/;

lib/tokenizer/tokenize-at-rule.js

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { atEndPattern, openedCurlyBracket, variablePattern, wordEndPattern } from './globals';
1+
import { atEndPattern, openedCurlyBracket, pageSelectorPattern, variableSpaceColonPattern, variablePattern, wordEndPattern } from './globals';
22
import unclosed from './unclosed';
33

44
export default function tokenizeAtRule (state) {
@@ -40,7 +40,19 @@ export default function tokenizeAtRule (state) {
4040
state.nextPos = state.css.length - 1;
4141
}
4242
else {
43-
state.nextPos = atEndPattern.lastIndex - 2;
43+
// the first condition below is special for variable in less
44+
// some one may write code like `@testVar : #fff`
45+
// we should detect this kind of existence.
46+
const rest = state.css.slice(atEndPattern.lastIndex);
47+
const potentialPageRule = state.css.slice(state.pos, atEndPattern.lastIndex + 1);
48+
49+
// we have to handle special selector like `@page :left`
50+
if (variableSpaceColonPattern.test(rest) && !pageSelectorPattern.test(potentialPageRule)) {
51+
state.nextPos = atEndPattern.lastIndex + rest.search(':');
52+
}
53+
else {
54+
state.nextPos = atEndPattern.lastIndex - 2;
55+
}
4456
}
4557

4658
state.cssPart = state.css.slice(state.pos, state.nextPos + 1);

test/parser/variables.spec.js

+60-30
Original file line numberDiff line numberDiff line change
@@ -24,39 +24,69 @@ describe('Parser', () => {
2424
});
2525

2626
// #98 was merged to resolve this but broke other scenarios
27-
it('parses variables with whitespaces between name and ":"'); //, () => {
28-
// let root = parse('@onespace : 42;');
29-
//
30-
// expect(root.first.prop).to.eql('@onespace');
31-
// expect(root.first.value).to.eql('42');
32-
// });
27+
it('parses variables with whitespaces between name and ":"', () => {
28+
let root = parse('@onespace : 42;');
29+
30+
expect(root.first.prop).to.eql('@onespace');
31+
expect(root.first.value).to.eql('42');
32+
});
3333

3434
// #98 was merged to resolve this but broke other scenarios
3535
// these tests are commented out until that is resolved
36-
it('parses variables with no whitespace between ":" and value'); //, () => {
37-
// const root = parse('@var :42;');
38-
//
39-
// expect(root.first.prop).to.eql('@var');
40-
// expect(root.first.value).to.eql('42');
41-
// });
42-
//
43-
it('parses mutliple variables with whitespaces between name and ":"'); //, () => {
44-
// const root = parse('@foo : 42; @bar : 35;');
45-
//
46-
// expect(root.first.prop).to.eql('@foo');
47-
// expect(root.first.value).to.eql('42');
48-
// expect(root.nodes[1].prop).to.eql('@bar');
49-
// expect(root.nodes[1].value).to.eql('35');
50-
// });
51-
//
52-
it('parses multiple variables with no whitespace between ":" and value'); //, () => {
53-
// const root = parse('@foo :42; @bar :35');
54-
//
55-
// expect(root.first.prop).to.eql('@foo');
56-
// expect(root.first.value).to.eql('42');
57-
// expect(root.nodes[1].prop).to.eql('@bar');
58-
// expect(root.nodes[1].value).to.eql('35');
59-
// });
36+
it('parses variables with no whitespace between ":" and value', () => {
37+
const root = parse('@var :42;');
38+
39+
expect(root.first.prop).to.eql('@var');
40+
expect(root.first.value).to.eql('42');
41+
});
42+
43+
it('parses mutliple variables with whitespaces between name and ":"', () => {
44+
const root = parse('@foo : 42; @bar : 35;');
45+
46+
expect(root.first.prop).to.eql('@foo');
47+
expect(root.first.value).to.eql('42');
48+
expect(root.nodes[1].prop).to.eql('@bar');
49+
expect(root.nodes[1].value).to.eql('35');
50+
});
51+
52+
it('parses multiple variables with no whitespace between ":" and value', () => {
53+
const root = parse('@foo :42; @bar :35');
54+
55+
expect(root.first.prop).to.eql('@foo');
56+
expect(root.first.value).to.eql('42');
57+
expect(root.nodes[1].prop).to.eql('@bar');
58+
expect(root.nodes[1].value).to.eql('35');
59+
});
60+
61+
it('parses @pagexxx like variable but not @page selector', () => {
62+
const root = parse('@pageWidth: "test";');
63+
64+
expect(root.first.prop).to.eql('@pageWidth');
65+
expect(root.first.value).to.eql('"test"');
66+
67+
const root2 = parse('@page-width: "test";');
68+
69+
expect(root2.first.prop).to.eql('@page-width');
70+
expect(root2.first.value).to.eql('"test"');
71+
});
72+
73+
it('parses @pagexxx like variable with whitespaces between name and ":"', () => {
74+
const root = parse('@pageWidth :"test";');
75+
76+
expect(root.first.prop).to.eql('@pageWidth');
77+
expect(root.first.value).to.eql('"test"');
78+
79+
const root2 = parse('@page-width :"test";');
80+
81+
expect(root2.first.prop).to.eql('@page-width');
82+
expect(root2.first.value).to.eql('"test"');
83+
84+
const root3 = parse('@page-width : "test";');
85+
86+
expect(root3.first.prop).to.eql('@page-width');
87+
expect(root3.first.value).to.eql('"test"');
88+
});
89+
6090

6191
it('parses string variables', () => {
6292
const root = parse('@var: "test";');

0 commit comments

Comments
 (0)