Skip to content

Commit 20955c1

Browse files
committed
add test for specialcharacters in selectors
1 parent e53f8ca commit 20955c1

File tree

6 files changed

+103
-38
lines changed

6 files changed

+103
-38
lines changed

index.js

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict';
22

33
var postcss = require('postcss');
4-
// /*DEBUG*/ var appendout = require('fs').appendFileSync;
4+
// /*DEBUG*/var appendout = require('fs').appendFileSync;
55

66
module.exports = postcss.plugin('postcss-extend', function extend() {
77

@@ -11,7 +11,7 @@ module.exports = postcss.plugin('postcss-extend', function extend() {
1111
var recurseStack = [];
1212
var isAntiPatternCSS = false;
1313

14-
// /*DEBUG*/ appendout('./test/debugout.txt', '\n----------------------------------------');
14+
// /*DEBUG*/appendout('./test/debugout.txt', '\n----------------------------------------');
1515

1616
css.walkAtRules(function(atRule) {
1717
if (definingAtRules.indexOf(atRule.name) !== -1) {
@@ -35,8 +35,8 @@ module.exports = postcss.plugin('postcss-extend', function extend() {
3535
}
3636
} else if (tgtSaved.length === 1) {
3737
targetNode.remove();
38-
// /*DEBUG*/ } else {
39-
// /*DEBUG*/ appendout('./test/debugout.txt', '\nSifted out placeholder/silent ' + tgtSaved[i]);
38+
// /*DEBUG*/} else {
39+
// /*DEBUG*/appendout('./test/debugout.txt', '\nSifted out placeholder/silent ' + tgtSaved[i]);
4040
}
4141
}
4242
if (selectorAccumulator) {
@@ -65,7 +65,7 @@ module.exports = postcss.plugin('postcss-extend', function extend() {
6565
definition.append(clone);
6666
});
6767
definition.selector = '@define-placeholder ' + atRule.params.toString();
68-
// /*DEBUG*/ appendout('./test/debugout.txt', '\nDeclaring placeholder : ' + definition.selector);
68+
// /*DEBUG*/appendout('./test/debugout.txt', '\nDeclaring placeholder : ' + definition.selector);
6969
atRule.parent.insertBefore(atRule, definition);
7070
atRule.remove();
7171
}
@@ -93,9 +93,9 @@ module.exports = postcss.plugin('postcss-extend', function extend() {
9393
//Strip all @define-placeholders and save slug-selectors present in tgtSaved
9494
for (var i = 0; i < tgtSaved.length; i++) {
9595
if (tgtSaved[i].substring(0, 20) === '@define-placeholder ') {
96-
// /*DEBUG*/ appendout('./test/debugout.txt', '\nn[' + i + ']String = ' + tgtSaved[i] + ' Substring 0-20 = \'' + tgtSaved[i].substring(0, 20) + '\'');
96+
// /*DEBUG*/appendout('./test/debugout.txt', '\nn[' + i + ']String = ' + tgtSaved[i] + ' Substring 0-20 = \'' + tgtSaved[i].substring(0, 20) + '\'');
9797
tgtSaved[i] = tgtSaved[i].substring(20, (tgtSaved[i].length));
98-
// /*DEBUG*/ appendout('./test/debugout.txt', '\nresString = \'' + tgtSaved[i] + '\'');
98+
// /*DEBUG*/appendout('./test/debugout.txt', '\nresString = \'' + tgtSaved[i] + '\'');
9999
}
100100
}
101101
var tgtAccumulate = targetNode.selectors;
@@ -106,15 +106,15 @@ module.exports = postcss.plugin('postcss-extend', function extend() {
106106
//check if target has unresolved extensions, then extend them
107107
if (extensionRecursionHandler(atRule, targetNode)) {
108108
//We need to re-evaluate the current atRule, as other classes (once passed over) may now be matching, so re-process and exit.
109-
// /*DEBUG*/ appendout('./test/debugout.txt', '\n!Bumping evaluation of :' + atRule.parent);
109+
// /*DEBUG*/appendout('./test/debugout.txt', '\n!Bumping evaluation of :' + atRule.parent);
110110
processExtension(atRule);
111111
couldExtend = true;
112112
return;
113113
}
114-
// /*DEBUG*/ appendout('./test/debugout.txt', '\nfound and extending : ' + tgtSaved[n] + ' : ' + originSels);
114+
// /*DEBUG*/appendout('./test/debugout.txt', '\nfound and extending : ' + tgtSaved[n] + ' : ' + originSels);
115115

116116
tgtAccumulate = tgtAccumulate.concat(originSels);
117-
// /*DEBUG*/ appendout('./test/debugout.txt', '\nCombined selectors :\n' + tgtAccumulate);
117+
// /*DEBUG*/appendout('./test/debugout.txt', '\nCombined selectors :\n' + tgtAccumulate);
118118
couldExtend = true;
119119
//Operate on sub-elements of extendables (thus extending them)
120120
} else if (tgtSaved[n].substring(1).search(/[\s.:#]/) + 1 !== -1) {
@@ -124,32 +124,32 @@ module.exports = postcss.plugin('postcss-extend', function extend() {
124124
//check if target rule has unresolved extensions, then extend them
125125
if (extensionRecursionHandler(atRule, targetNode)) {
126126
//We need to re-evaluate the current atRule, as other classes (once passed over) may now be matching, so re-process and exit.
127-
// /*DEBUG*/ appendout('./test/debugout.txt', '\n!Bumping evaluation of :' + atRule.parent);
127+
// /*DEBUG*/appendout('./test/debugout.txt', '\n!Bumping evaluation of :' + atRule.parent);
128128
processExtension(atRule);
129129
couldExtend = true;
130130
return;
131131
}
132132
//tack onto target node
133-
// /*DEBUG*/ appendout('./test/debugout.txt', '\nfound and extending : ' + tgtSaved[n].substring(0, tgtSaved[n].substring(1).search(/[\s.:#]/) + 1) + ' :\n' + tgtBase + ' (' + tgtSub + ')');
133+
// /*DEBUG*/appendout('./test/debugout.txt', '\nfound and extending : ' + tgtSaved[n].substring(0, tgtSaved[n].substring(1).search(/[\s.:#]/) + 1) + ' :\n' + tgtBase + ' (' + tgtSub + ')');
134134

135-
// /*DEBUG*/ appendout('./test/debugout.txt', '\nCalling formSubSelector with (\n' + originSels + ',\n' + tgtSub);
135+
// /*DEBUG*/appendout('./test/debugout.txt', '\nCalling formSubSelector with (\n' + originSels + ',\n' + tgtSub);
136136
tgtAccumulate = tgtAccumulate.concat(formSubSelector(originSels, tgtSub));
137-
// /*DEBUG*/ appendout('./test/debugout.txt', '\nCombined selectors :\n' + tgtAccumulate);
137+
// /*DEBUG*/appendout('./test/debugout.txt', '\nCombined selectors :\n' + tgtAccumulate);
138138
couldExtend = true;
139139
}
140140
}//END OF sub root-extensions
141141
}
142142
if (couldExtend) {
143-
// /*DEBUG*/ appendout('./test/debugout.txt', '\nStart uniqreq2 :\n' + tgtAccumulate);
143+
// /*DEBUG*/appendout('./test/debugout.txt', '\nStart uniqreq2 :\n' + tgtAccumulate);
144144
//Kill off duplicate selectors
145145
tgtAccumulate = uniqreq(tgtAccumulate).toString().replace(/,/g, ', ');
146-
// /*DEBUG*/ appendout('./test/debugout.txt', '\nPost uniqreq2 :\n' + tgtAccumulate);
146+
// /*DEBUG*/appendout('./test/debugout.txt', '\nPost uniqreq2 :\n' + tgtAccumulate);
147147
targetNode.selector = tgtAccumulate;
148148
}
149149
});
150150
//hasMediaAncestor === true: ---------------
151151
} else {
152-
// /*DEBUG*/ appendout('./test/debugout.txt', '\nAttempting to fetch declarations for ' + atRule.params + '...');
152+
// /*DEBUG*/appendout('./test/debugout.txt', '\nAttempting to fetch declarations for ' + atRule.params + '...');
153153
var backFirstTargetNode;
154154
var targetNodeArray = [];
155155
css.walkRules(function(subRule) {
@@ -177,19 +177,19 @@ module.exports = postcss.plugin('postcss-extend', function extend() {
177177
//check if rule has unresolved extensions, then extend them
178178
if (extensionRecursionHandler(atRule, backFirstTargetNode)) {
179179
//We need to re-evaluate the current atRule, as other classes (once passed over) may now be matching, so re-process and exit.
180-
// /*DEBUG*/ appendout('./test/debugout.txt', '\n!Bumping evaluation of :' + atRule.parent);
180+
// /*DEBUG*/appendout('./test/debugout.txt', '\n!Bumping evaluation of :' + atRule.parent);
181181
processExtension(atRule);
182182
couldExtend = true;
183183
return;
184184
}
185185
//In scope, tack on selector to target rule
186186
if (backFirstTargetNode.parent === atRule.parent.parent) {
187-
// /*DEBUG*/ appendout('./test/debugout.txt', '\n...tacking onto backFirstTargetNode :' + backFirstTargetNode);
187+
// /*DEBUG*/appendout('./test/debugout.txt', '\n...tacking onto backFirstTargetNode :' + backFirstTargetNode);
188188
selectorRetainer = backFirstTargetNode.selectors;
189189
backFirstTargetNode.selector = uniqreq(selectorRetainer.concat(originSels)).join(', ');
190190
//Out of scope, direcly copy declarations
191191
} else {
192-
// /*DEBUG*/ appendout('./test/debugout.txt', '\n...grabbing backFirstTargetNode :\n' + backFirstTargetNode);
192+
// /*DEBUG*/appendout('./test/debugout.txt', '\n...grabbing backFirstTargetNode :\n' + backFirstTargetNode);
193193
safeCopyDeclarations(backFirstTargetNode, atRule.parent);
194194
}
195195
couldExtend = true;
@@ -202,26 +202,26 @@ module.exports = postcss.plugin('postcss-extend', function extend() {
202202
//check if target rule has unresolved extensions, then extend them
203203
if (extensionRecursionHandler(atRule, backFirstTargetNode)) {
204204
//We need to re-evaluate the current atRule, as other classes (once passed over) may now be matching, so re-process and exit.
205-
// /*DEBUG*/ appendout('./test/debugout.txt', '\n!Bumping evaluation of :' + atRule.parent);
205+
// /*DEBUG*/appendout('./test/debugout.txt', '\n!Bumping evaluation of :' + atRule.parent);
206206
processExtension(atRule);
207207
couldExtend = true;
208208
return;
209209
}
210210
if (backFirstTargetNode.parent === atRule.parent.parent) {
211211
//Use Tacking onto exiting selectors instead of new creation
212-
// /*DEBUG*/ appendout('./test/debugout.txt', '\nUtilizing existing brother subclass for extension, as nothing matches: \n' + atRule.parent.selector + ' sub-' + extTgtSub);
212+
// /*DEBUG*/appendout('./test/debugout.txt', '\nUtilizing existing brother subclass for extension, as nothing matches: \n' + atRule.parent.selector + ' sub-' + extTgtSub);
213213
selectorRetainer = backFirstTargetNode.selectors;
214214
backFirstTargetNode.selector = uniqreq(selectorRetainer.concat(formSubSelector(originSels, extTgtSub))).join(', ');
215215
} else {
216216
//check for prexisting sub classes before making one
217217
subTarget = findBrotherSubClass(atRule.parent, extTgtSub);
218218
if (subTarget.bool) {
219219
//utilize existing subclass for extension
220-
// /*DEBUG*/ appendout('./test/debugout.txt', '\nUtilizing existing subclass for extension:\n' + subTarget.selector);
220+
// /*DEBUG*/appendout('./test/debugout.txt', '\nUtilizing existing subclass for extension:\n' + subTarget.selector);
221221
safeCopyDeclarations(backFirstTargetNode, subTarget.node);
222222
} else {
223223
//create additional nodes below existing for each instance of subs
224-
// /*DEBUG*/ appendout('./test/debugout.txt', '\nUtilizing new subclass for extension, as nothing matches: \n' + atRule.parent.selector + ' sub-' + extTgtSub);
224+
// /*DEBUG*/appendout('./test/debugout.txt', '\nUtilizing new subclass for extension, as nothing matches: \n' + atRule.parent.selector + ' sub-' + extTgtSub);
225225
var newNode = postcss.rule();
226226
newNode.semicolon = atRule.semicolon;
227227
safeCopyDeclarations(backFirstTargetNode, newNode);
@@ -237,7 +237,7 @@ module.exports = postcss.plugin('postcss-extend', function extend() {
237237
} //end of if hasMediaAncestor
238238
if (!couldExtend) {
239239
result.warn('\'' + atRule.params + '\', has not been defined, so it cannot be extended', { node: atRule });
240-
// /*DEBUG*/ appendout('./test/debugout.txt', '\n\'' + atRule.params + '\' has not been defined!!!');
240+
// /*DEBUG*/appendout('./test/debugout.txt', '\n\'' + atRule.params + '\' has not been defined!!!');
241241
}
242242
if (atRule.parent !== undefined) {
243243
if (!atRule.parent.nodes.length || atRule.parent.nodes.length === 1) {
@@ -287,7 +287,7 @@ module.exports = postcss.plugin('postcss-extend', function extend() {
287287

288288
function isBadExtensionPair(atRule, targetNode) {
289289
if (hasMediaAncestor(targetNode) && hasMediaAncestor(atRule) && targetNode.parent !== atRule.parent.parent) {
290-
// /*DEBUG*/ appendout('./test/debugout.txt', '\nMEDIA2MEDIA extention detected, node :\n' + atRule.parent);
290+
// /*DEBUG*/appendout('./test/debugout.txt', '\nMEDIA2MEDIA extention detected, node :\n' + atRule.parent);
291291
result.warn('@extend was called to extend something in an @media from within another @media, this was safely ignored. For more information see the README under \'Quirks\'', {node: atRule});
292292
return true;
293293
}
@@ -317,10 +317,10 @@ module.exports = postcss.plugin('postcss-extend', function extend() {
317317
nodeOrigin.nodes.forEach(function(node) {
318318
if (isBadDefinitionNode(node)) return;
319319
if (nodeDest.some(function(decl) { return decl.prop === node.prop; })) {
320-
// /*DEBUG*/ appendout('./test/debugout.txt', '\nsafeIgnored : ' + node + ' for ' + nodeDest.selector);
320+
// /*DEBUG*/appendout('./test/debugout.txt', '\nsafeIgnored : ' + node + ' for ' + nodeDest.selector);
321321
return;
322322
}
323-
// /*DEBUG*/ appendout('./test/debugout.txt', '\nnodeDest Nodes:\n' + nodeDest.nodes);
323+
// /*DEBUG*/appendout('./test/debugout.txt', '\nnodeDest Nodes:\n' + nodeDest.nodes);
324324
var clone = node.clone();
325325
//For lack of a better way to analyse how much tabbing is required:
326326
if (nodeOrigin.parent === nodeDest.parent) {
@@ -364,12 +364,12 @@ module.exports = postcss.plugin('postcss-extend', function extend() {
364364
// Throw this error only once, and only if it's an antipattern
365365
// Make sure index could be obtained for atRule parent
366366
if (css.index(atRule.parent) !== -1) {
367-
// /*DEBUG*/ appendout('./test/debugout.txt', '\nANTIPATTERN CSS detected parent at: ' + css.index(atRule.parent) + ' target at: ' + css.index(targetNode) + ' parent :\n' + atRule.parent);
367+
// /*DEBUG*/appendout('./test/debugout.txt', '\nANTIPATTERN CSS detected parent at: ' + css.index(atRule.parent) + ' target at: ' + css.index(targetNode) + ' parent :\n' + atRule.parent);
368368
result.warn('@extend is being used in an anti-pattern (extending things not yet defined). This is your first and final warning', {node: atRule});
369369
isAntiPatternCSS = true;
370370
// If index couldn't be obtained on atRule, check up the chain a step
371371
} else if (css.index(atRule.parent.parent) !== -1 && css.index(atRule.parent.parent) < css.index(targetNode)) {
372-
// /*DEBUG*/ appendout('./test/debugout.txt', '\nANTIPATTERN CSS detected parent\'s parent at: ' + css.index(atRule.parent.parent) + ' target at: ' + css.index(targetNode) + ' parent :\n' + atRule.parent);
372+
// /*DEBUG*/appendout('./test/debugout.txt', '\nANTIPATTERN CSS detected parent\'s parent at: ' + css.index(atRule.parent.parent) + ' target at: ' + css.index(targetNode) + ' parent :\n' + atRule.parent);
373373
result.warn('@extend is being used in an anti-pattern (extending things not yet defined). This is your first and final warning', {node: atRule});
374374
isAntiPatternCSS = true;
375375
}
@@ -378,33 +378,33 @@ module.exports = postcss.plugin('postcss-extend', function extend() {
378378
recurseStack.push(atRule.params);
379379
while (recursableRule.bool) {
380380
if (recurseStack.indexOf(recursableRule.node.params) === -1) {
381-
// /*DEBUG*/ appendout('./test/debugout.txt', '\nRecursing from ' + atRule.parent.selector + ' on: ' + recursableRule.node.parent + '\n\\/\\/\\/\\/\\/\\/\\/\\/ ' + recurseStack);
381+
// /*DEBUG*/appendout('./test/debugout.txt', '\nRecursing from ' + atRule.parent.selector + ' on: ' + recursableRule.node.parent + '\n\\/\\/\\/\\/\\/\\/\\/\\/ ' + recurseStack);
382382
processExtension(recursableRule.node);
383-
// /*DEBUG*/ appendout('./test/debugout.txt', '\n ^ ^ ^ ^ ^ ^ ^ ^ ' + recurseStack);
383+
// /*DEBUG*/appendout('./test/debugout.txt', '\n ^ ^ ^ ^ ^ ^ ^ ^ ' + recurseStack);
384384
// In case of slippage in processExtention recursion, clean up @extend
385385
if (recursableRule.node !== undefined) {
386-
// /*DEBUG*/ appendout('./test/debugout.txt', '\npreventing slippage in recursion by removing resolved :' + recursableRule.node);
386+
// /*DEBUG*/appendout('./test/debugout.txt', '\npreventing slippage in recursion by removing resolved :' + recursableRule.node);
387387
recursableRule.node.remove();
388388
}
389389
recursableRule = findUnresolvedExtendChild(targetNode);
390390
} else {
391391
result.warn('Infinite extension recursion detected', { node: atRule });
392-
// /*DEBUG*/ appendout('./test/debugout.txt', '\nInfinite Recursion detected, recurseStack : ' + recurseStack + '\n -- on :\n' + atRule.parent + '\n!!!!!!!!!!!!');
392+
// /*DEBUG*/appendout('./test/debugout.txt', '\nInfinite Recursion detected, recurseStack : ' + recurseStack + '\n -- on :\n' + atRule.parent + '\n!!!!!!!!!!!!');
393393
//clean out the recurse stack of duplicates (from early aborts like this) before dropping
394394
recurseStack = uniqreq(recurseStack);
395395
return false;
396396
}
397397
}
398398

399-
// /*DEBUG*/ appendout('./test/debugout.txt', '\npre-pop recurseStack : ' + recurseStack);
399+
// /*DEBUG*/appendout('./test/debugout.txt', '\npre-pop recurseStack : ' + recurseStack);
400400
if (recurseStack.pop() !== atRule.params && recurseStack.indexOf(atRule.params) === -1) {
401401
result.warn('Detected critically mis-aligned recursion stack! (Please post your CSS in a github issue, this shouldn\'t ever happen!)', { node: atRule });
402-
// /*DEBUG*/ appendout('./test/debugout.txt', '\n!!!!!!!!!!!!CRITICALLY MISALIGNED RECURSE STACK\nexpected : ' + atRule.params + '\npost-pop recurseStack : ' + recurseStack);
402+
// /*DEBUG*/appendout('./test/debugout.txt', '\n!!!!!!!!!!!!CRITICALLY MISALIGNED RECURSE STACK\nexpected : ' + atRule.params + '\npost-pop recurseStack : ' + recurseStack);
403403
}
404404
//Empty history if this is top of a recursion (as process preserves detections as it backs-out)
405405
if (isTopOfRecurse) {
406406
recurseStack = [];
407-
// /*DEBUG*/ appendout('./test/debugout.txt', '\nrecurseStack dumped, at top');
407+
// /*DEBUG*/appendout('./test/debugout.txt', '\nrecurseStack dumped, at top');
408408
}
409409
return true;
410410
}
@@ -422,7 +422,7 @@ module.exports = postcss.plugin('postcss-extend', function extend() {
422422
if (node !== nodeOrigin && selectorAccumulator.length === node.selectors.length) {
423423
seldiff = seldiff.concat(selectorAccumulator);
424424
seldiff = uniqreq(seldiff);
425-
// /*DEBUG*/ appendout('./test/debugout.txt', '\nseldiff : ' + seldiff + '\n\tBetween:\n' + node.selectors + '\n\tand:\n' + selectorAccumulator);
425+
// /*DEBUG*/appendout('./test/debugout.txt', '\nseldiff : ' + seldiff + '\n\tBetween:\n' + node.selectors + '\n\tand:\n' + selectorAccumulator);
426426
if (seldiff.length === selectorAccumulator.length) {
427427
foundNode = node;
428428
return true;

test/fixtures/specialchars-direct.css

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.dark-#$%^&*blue-background {
2+
background-color: #004a6b;
3+
color: white;
4+
box-shadow: rgba(255, 255, 255, 0.11) 0 -30px 60px inset;
5+
}
6+
7+
.person__header {
8+
@extend .dark-#$%^&*blue-background;
9+
padding: 20px 0 1em;
10+
height: 12vh;
11+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.dark-#$%^&*blue-background, .person__header {
2+
background-color: #004a6b;
3+
color: white;
4+
box-shadow: rgba(255, 255, 255, 0.11) 0 -30px 60px inset;
5+
}
6+
7+
.person__header {
8+
padding: 20px 0 1em;
9+
height: 12vh;
10+
}

0 commit comments

Comments
 (0)