Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

postcss-extend

Package Overview
Dependencies
Maintainers
2
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

postcss-extend - npm Package Compare versions

Comparing version 0.4.2 to 0.4.3

7

CHANGELOG.md
# Changelog
## v0.4.1
- [Infinite recursion detection improvements, widespread minor corrections](https://github.com/travco/postcss-extend/releases/tag/v0.4.1)
## v0.4.3
- [Antipattern CSS detection and warning, and media-cross-media warning](https://github.com/travco/postcss-extend/releases/tag/v0.4.3)
## v0.4.2
- [Infinite recursion detection improvements, widespread minor corrections](https://github.com/travco/postcss-extend/releases/tag/v0.4.2)
## v0.4.0

@@ -7,0 +10,0 @@ - [All-intended-features release as 'postcss-extend'](https://github.com/travco/postcss-extend/releases/tag/v0.4.0)

@@ -11,2 +11,3 @@ 'use strict';

var recurseStack = [];
var isAntiPatternCSS = false;

@@ -21,2 +22,4 @@ css.eachAtRule(function(atRule) {

//Selectively disclude silents and placeholders, find unused,
//and exclude from the final output
css.eachRule(function(targetNode) {

@@ -41,2 +44,3 @@ var tgtSaved = targetNode.selectors;

//simplification process to find definitions in the future
function processDefinition(atRule) {

@@ -49,2 +53,5 @@ if (isBadDefinitionLocation(atRule)) {

//Manually copy styling properties (semicolon, whitespace)
//to newly created and cloned nodes,
//cf. https://github.com/postcss/postcss/issues/85
definition.semicolon = atRule.semicolon;

@@ -84,2 +91,3 @@ atRule.nodes.forEach(function(node) {

var tgtSaved = targetNode.selectors;
//Strip all @define-placeholders and save slug-selectors present in tgtSaved
for (var i = 0; i < tgtSaved.length; i++) {

@@ -93,4 +101,7 @@ if (tgtSaved[i].substring(0, 20) === '@define-placeholder ') {

for (var n = 0; n < tgtSaved.length; n++) {
//Operate on normal extendables
if (atRule.params === tgtSaved[n]) {
//check if target has unresolved extensions, then extend them
if (extensionRecursionHandler(atRule, targetNode)) {
//We need to re-evaluate the current atRule, as other classes (once passed over) may now be matching, so re-process and exit.
processExtension(atRule);

@@ -103,2 +114,3 @@ couldExtend = true;

couldExtend = true;
//Operate on sub-elements of extendables (thus extending them)
} else if (tgtSaved[n].substring(1).search(/[\s.:#]/) + 1 !== -1) {

@@ -108,3 +120,5 @@ var tgtBase = tgtSaved[n].substring(0, tgtSaved[n].substring(1).search(/[\s.:#]/) + 1);

if (atRule.params === tgtBase) {
//check if target rule has unresolved extensions, then extend them
if (extensionRecursionHandler(atRule, targetNode)) {
//We need to re-evaluate the current atRule, as other classes (once passed over) may now be matching, so re-process and exit.
processExtension(atRule);

@@ -114,13 +128,16 @@ couldExtend = true;

}
//tack onto target node
tgtAccumulate = tgtAccumulate.concat(formSubSelector(originSels, tgtSub));
couldExtend = true;
}
}
}//END OF sub root-extensions
}
if (couldExtend) {
//Kill off duplicate selectors
tgtAccumulate = uniqreq(tgtAccumulate).toString().replace(/,/g, ', ');
// /*DEBUG*/ appendout('./test/debugout.txt', '\nPost uniqreq2 :\n' + tgtAccumulate);
targetNode.selector = tgtAccumulate;
}
});
//hasMediaAncestor === true: ---------------
} else {

@@ -130,10 +147,26 @@ var backFirstTargetNode;

css.eachRule(function(subRule) {
//create a back-is-top stack so that we can efficiently operate on nodes in reverse
//thus retaining priority when copying declarations if there are multiple matches
if (!hasMediaAncestor(subRule) || subRule.parent === atRule.parent.parent) {
targetNodeArray.push(subRule);
//If is in @media extending another @media and is a targeted rule (two phase):
//check for an illegal extention, and then don't process that node.
} else if (subRule.selectors.indexOf(atRule.params) !== -1) {
isBadExtensionPair(atRule, subRule);
} else {
for (var s = 0; s < subRule.selectors.length; s++) {
if (subRule.selectors[s].substring(1).search(/[\s.:#]/) + 1 !== -1 && subRule.selectors[s].substring(0, subRule.selectors[s].substring(1).search(/[\s.:#]/) + 1) === atRule.params) {
isBadExtensionPair(atRule, subRule);
break;
}
}
}
});
}); //end of each rule
while (targetNodeArray.length > 0) {
backFirstTargetNode = targetNodeArray.pop();
if (backFirstTargetNode.selectors.indexOf(atRule.params) !== -1) {
//check if rule has unresolved extensions, then extend them
if (extensionRecursionHandler(atRule, backFirstTargetNode)) {
//We need to re-evaluate the current atRule, as other classes (once passed over) may now be matching, so re-process and exit.
processExtension(atRule);

@@ -143,5 +176,7 @@ couldExtend = true;

}
//In scope, tack on selector to target rule
if (backFirstTargetNode.parent === atRule.parent.parent) {
selectorRetainer = backFirstTargetNode.selectors;
backFirstTargetNode.selector = uniqreq(selectorRetainer.concat(originSels)).join(', ');
//Out of scope, direcly copy declarations
} else {

@@ -152,2 +187,3 @@ safeCopyDeclarations(backFirstTargetNode, atRule.parent);

} else {
//Pull from sub-elements of target nodes (thus extending them)
for (var m = 0; m < backFirstTargetNode.selectors.length; m++) {

@@ -157,3 +193,5 @@ var extTgtBase = backFirstTargetNode.selectors[m].substring(0, backFirstTargetNode.selectors[m].substring(1).search(/[\s.:#]/) + 1);

if (backFirstTargetNode.selectors[m].substring(1).search(/[\s.:#]/) + 1 !== -1 && extTgtBase === atRule.params) {
//check if target rule has unresolved extensions, then extend them
if (extensionRecursionHandler(atRule, backFirstTargetNode)) {
//We need to re-evaluate the current atRule, as other classes (once passed over) may now be matching, so re-process and exit.
processExtension(atRule);

@@ -164,9 +202,13 @@ couldExtend = true;

if (backFirstTargetNode.parent === atRule.parent.parent) {
//Use Tacking onto exiting selectors instead of new creation
selectorRetainer = backFirstTargetNode.selectors;
backFirstTargetNode.selector = uniqreq(selectorRetainer.concat(formSubSelector(originSels, extTgtSub))).join(', ');
} else {
//check for prexisting sub classes before making one
subTarget = findBrotherSubClass(atRule.parent, extTgtSub);
if (subTarget.bool) {
//utilize existing subclass for extension
safeCopyDeclarations(backFirstTargetNode, subTarget.node);
} else {
//create additional nodes below existing for each instance of subs
var newNode = postcss.rule();

@@ -184,5 +226,5 @@ newNode.semicolon = atRule.semicolon;

}
}
} //end of if hasMediaAncestor
if (!couldExtend) {
result.warn('\'' + atRule.params + '\', has not been defined, so cannot be extended');
result.warn('\'' + atRule.params + '\', has not been defined, so it cannot be extended');
}

@@ -235,2 +277,9 @@ if (atRule.parent !== undefined) {

function isBadExtensionPair(atRule, targetNode) {
if (hasMediaAncestor(targetNode) && hasMediaAncestor(atRule) && targetNode.parent !== atRule.parent.parent) {
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: targetNode});
return true;
}
}
function hasMediaAncestor(node) {

@@ -263,2 +312,3 @@ var parent = node.parent;

var clone = node.clone();
//For lack of a better way to analyse how much tabbing is required:
if (nodeOrigin.parent === nodeDest.parent) {

@@ -301,2 +351,7 @@ clone.before = node.before;

if (recurseStack.length === 0) { isTopOfRecurse = true; }
if (!isAntiPatternCSS && css.index(atRule.parent) < css.index(targetNode)) {
//throw this error only once, and only if it's an antipattern
result.warn('@extend is being used in an anti-pattern (extending things not yet defined). This is your first and final warning', {node: atRule.parent});
isAntiPatternCSS = true;
}
if (recursableRule.bool) {

@@ -310,2 +365,3 @@ recurseStack.push(atRule.params);

result.warn('Infinite extension recursion detected', { node: atRule });
//clean out the recurse stack of duplicates (from early aborts like this) before dropping
recurseStack = uniqreq(recurseStack);

@@ -319,2 +375,3 @@ return false;

}
//Empty history if this is top of a recursion (as process preserves detections as it backs-out)
if (isTopOfRecurse) {

@@ -321,0 +378,0 @@ recurseStack = [];

@@ -8,4 +8,4 @@ {

"license": "MIT",
"version": "0.4.2",
"description": "Simple extends for PostCSS",
"version": "0.4.3",
"description": "As close to cssnext @extend as possible for PostCSS",
"homepage": "https://github.com/travco/postcss-extend",

@@ -12,0 +12,0 @@ "repository": {

@@ -287,3 +287,3 @@ # postcss-extend [![Build Status](https://travis-ci.org/travco/postcss-extend.svg?branch=master)](https://travis-ci.org/travco/postcss-extend)

**Don't**. It's currently directly-disallowed in code to prevent unexpected things from happening. The current expectation is that the only time majority of users would do this is when making a mistake. That expectation remains unless someone can present a solution and a logical way of handling this (not in the native CSS parser) that is also a realistic common-use case.
**Don't**. It's currently directly-disallowed in code to prevent unexpected things from happening, and will throw an error to warn you. The current expectation is that the only time majority of users would do this is when making a mistake. That expectation remains unless someone can present a solution and a logical way of handling this (not in the native CSS parser) that is also a realistic common-use case.

@@ -356,3 +356,3 @@ #### Chaining `@extend`s, or extension-recursion

**Order of Processing** : Currently, all of the `@extend`s being processed are run in a sequential manner from the top to the bottom of the doc. This keeps thing relatively snappy, but makes it so that we have to do conditional-recursion on not-yet-declared-or-extended rules. This leads to some blatant inefficiencies when processing badly formed CSS. So if you want to keep processing time down, write good CSS.
**Order of Processing** : Currently, all of the `@extend`s being processed are run in a sequential manner from the top to the bottom of the doc. This keeps thing relatively snappy, but makes it so that we have to do conditional-recursion on not-yet-declared-or-extended rules. This leads to some blatant inefficiencies when processing badly formed CSS (anti-pattern CSS). So if you want to keep processing time down, write good CSS. If you're curious if what you're writing is an anti-pattern, don't worry, it will throw a warning.

@@ -359,0 +359,0 @@ **Non-logical means of extension for `@media`** : As anyone who's aware of the complications discussed in the [SASS issue about extending across `@media`](https://github.com/sass/sass/issues/1050) would know. There is no way (known) of extending when `@media` rules are involved that is both 'clean and simple' and 'logically correct with how `@extend` is used elsewhere'. The way this plugin operates, and it's logical meaning, is a blatant compromise so that it has both common use cases and easier implementation. While the current implementations will not change (without flags), such things as extending an `@media` from within an `@media` does nothing, this could possibly change in the future.

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc