Skip to content

fix: handle whitespace between variable and colon #101

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 28, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/tokenizer/globals.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,7 @@ export const atEndPattern = /[ \n\t\r\f\{\(\)'"\\;/\[\]#]/g;
export const wordEndPattern = /[ \n\t\r\f\(\)\{\}:,;@!'"\\\]\[#]|\/(?=\*)/g;
export const badBracketPattern = /.[\\\/\("'\n]/;

export const pageSelectorPattern = /^@page[^\w-]+/;
export const variableSpaceColonPattern = /^\s*:/;
export const variablePattern = /^@[^:\(\{]+:/;
export const hashColorPattern = /^#[0-9a-fA-F]{6}$|^#[0-9a-fA-F]{3}$/;
16 changes: 14 additions & 2 deletions lib/tokenizer/tokenize-at-rule.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { atEndPattern, openedCurlyBracket, variablePattern, wordEndPattern } from './globals';
import { atEndPattern, openedCurlyBracket, pageSelectorPattern, variableSpaceColonPattern, variablePattern, wordEndPattern } from './globals';
import unclosed from './unclosed';

export default function tokenizeAtRule (state) {
Expand Down Expand Up @@ -40,7 +40,19 @@ export default function tokenizeAtRule (state) {
state.nextPos = state.css.length - 1;
}
else {
state.nextPos = atEndPattern.lastIndex - 2;
// the first condition below is special for variable in less
// some one may write code like `@testVar : #fff`
// we should detect this kind of existence.
const rest = state.css.slice(atEndPattern.lastIndex);
const potentialPageRule = state.css.slice(state.pos, atEndPattern.lastIndex + 1);

// we have to handle special selector like `@page :left`
if (variableSpaceColonPattern.test(rest) && !pageSelectorPattern.test(potentialPageRule)) {
state.nextPos = atEndPattern.lastIndex + rest.search(':');
}
else {
state.nextPos = atEndPattern.lastIndex - 2;
}
}

state.cssPart = state.css.slice(state.pos, state.nextPos + 1);
Expand Down
90 changes: 60 additions & 30 deletions test/parser/variables.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,39 +24,69 @@ describe('Parser', () => {
});

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

expect(root.first.prop).to.eql('@onespace');
expect(root.first.value).to.eql('42');
});

// #98 was merged to resolve this but broke other scenarios
// these tests are commented out until that is resolved
it('parses variables with no whitespace between ":" and value'); //, () => {
// const root = parse('@var :42;');
//
// expect(root.first.prop).to.eql('@var');
// expect(root.first.value).to.eql('42');
// });
//
it('parses mutliple variables with whitespaces between name and ":"'); //, () => {
// const root = parse('@foo : 42; @bar : 35;');
//
// expect(root.first.prop).to.eql('@foo');
// expect(root.first.value).to.eql('42');
// expect(root.nodes[1].prop).to.eql('@bar');
// expect(root.nodes[1].value).to.eql('35');
// });
//
it('parses multiple variables with no whitespace between ":" and value'); //, () => {
// const root = parse('@foo :42; @bar :35');
//
// expect(root.first.prop).to.eql('@foo');
// expect(root.first.value).to.eql('42');
// expect(root.nodes[1].prop).to.eql('@bar');
// expect(root.nodes[1].value).to.eql('35');
// });
it('parses variables with no whitespace between ":" and value', () => {
const root = parse('@var :42;');

expect(root.first.prop).to.eql('@var');
expect(root.first.value).to.eql('42');
});

it('parses mutliple variables with whitespaces between name and ":"', () => {
const root = parse('@foo : 42; @bar : 35;');

expect(root.first.prop).to.eql('@foo');
expect(root.first.value).to.eql('42');
expect(root.nodes[1].prop).to.eql('@bar');
expect(root.nodes[1].value).to.eql('35');
});

it('parses multiple variables with no whitespace between ":" and value', () => {
const root = parse('@foo :42; @bar :35');

expect(root.first.prop).to.eql('@foo');
expect(root.first.value).to.eql('42');
expect(root.nodes[1].prop).to.eql('@bar');
expect(root.nodes[1].value).to.eql('35');
});

it('parses @pagexxx like variable but not @page selector', () => {
const root = parse('@pageWidth: "test";');

expect(root.first.prop).to.eql('@pageWidth');
expect(root.first.value).to.eql('"test"');

const root2 = parse('@page-width: "test";');

expect(root2.first.prop).to.eql('@page-width');
expect(root2.first.value).to.eql('"test"');
});

it('parses @pagexxx like variable with whitespaces between name and ":"', () => {
const root = parse('@pageWidth :"test";');

expect(root.first.prop).to.eql('@pageWidth');
expect(root.first.value).to.eql('"test"');

const root2 = parse('@page-width :"test";');

expect(root2.first.prop).to.eql('@page-width');
expect(root2.first.value).to.eql('"test"');

const root3 = parse('@page-width : "test";');

expect(root3.first.prop).to.eql('@page-width');
expect(root3.first.value).to.eql('"test"');
});


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