New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

postcss-nested-ancestors

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

postcss-nested-ancestors - npm Package Compare versions

Comparing version 0.0.1 to 0.1.0

10

CHANGELOG.md

@@ -0,5 +1,11 @@

## 0.1.0
* Add experimental `replaceDeclarations` option, to process declaration props and values, too
* Cast warning when nestingLevel >= parentsStack.length
* Move `spacesAndAmpersandRegex` regex into a reusable regex
* Add a failing test case documenting issues when complex nesting
## 0.0.1
* Fix levelSymbol and parentSymbol options not being used.
* Fix `levelSymbol` and `parentSymbol` options not being used
## 0.0.0
* Initial release.
* Initial release

81

index.js

@@ -7,3 +7,4 @@ var postcss = require('postcss'),

opts = assign({
placeholder: '^&'
placeholder: '^&',
replaceDeclarations: false
}, opts);

@@ -18,12 +19,13 @@

var parentsStack = [],
// Get all ancestors placeholder recurrencies: ^&, ^^&, ^^^&, [...]
placeholderRegex = new RegExp(
/**
* Get all ancestors placeholder recurrencies:
* ^&, ^^&, ^^^&, [...]
*/
// eslint-disable-next-line max-len
'(' + escRgx(opts.levelSymbol) + ')+(' + escRgx(opts.parentSymbol) + ')',
'g'
);
),
// Get any space preceding an ampersand
spacesAndAmpersandRegex = /\s&/g;
/**

@@ -33,15 +35,21 @@ * Walk current ancestor stack and

*
* @param {Number} ancestor nesting depth ( 0 = &, 1 = grandparent, ...)
* @param {Number} ancestor nesting depth (0 = &, 1 = ^& = grandparent...)
* @param {Object} a PostCSS Rule object
* @param {Object} a PostCSS Result object
* @return {String} ancestor selector
*/
function getParentSelectorAtLevel(nestingLevel) {
function getParentSelectorAtLevel(nestingLevel, rule, result) {
nestingLevel = nestingLevel || 1;
// @TODO add warning when nestingLevel >= parentsStack.length
// Set a warning when nestingLevel >= parentsStack.length
if ( nestingLevel >= parentsStack.length ) {
rule.warn(result, 'Parent selector exceeds current stack.');
}
return parentsStack.filter( function (rule, index) {
// Create an array of matching parent selectors
return parentsStack.filter( function (selector, index) {
return index < parentsStack.length - nestingLevel;
})
.join(' ')
.replace(/\s&/g, ''); // Remove empty spaces before "&"
.replace(spacesAndAmpersandRegex, ''); // Remove " &"
}

@@ -54,9 +62,14 @@

*
* @param {String} placeholder eg.^^&
* @param {String} placeholder (eg.^^&)
* @param {Object} a PostCSS Rule object
* @param {Object} a PostCSS Result object
* @return {String} string ancestor selector fragment
*/
function placeholderReplacer(placeholder) {
function placeholderReplacer(placeholder, rule, result) {
return getParentSelectorAtLevel(
// Get how many level symbols ("^") has current placeholder
placeholder.split(opts.levelSymbol).length - 1
placeholder.split(opts.levelSymbol).length - 1,
rule,
result
);

@@ -66,37 +79,49 @@ }

/**
* Replace any ancestor placeholder into a given selector.
* Replace any ancestor placeholder into a given selector/string.
*
* @param {String} selector
* @param {String} CSS selector / string
* @param {Object} a PostCSS Rule object
* @param {Object} a PostCSS Result object
* @return {String} selector
*/
function replacePlaceholders(selector) {
function replacePlaceholders(selector, rule, result) {
// Find placeholders and replace them with matching parent selector
return selector.replace(
placeholderRegex,
placeholderReplacer
function (placeholder) {
return placeholderReplacer(placeholder, rule, result);
}
);
}
var process = function (node) {
var process = function (node, result) {
node.each( function (rule) {
if (rule.type === 'rule') {
// Add current parent selector to current parent stack
if (rule.parent.type === 'rule') {
parentsStack.push(rule.parent.selector);
}
// Replace parents placeholders in rule selectors
rule.selector = replacePlaceholders(rule.selector, rule, result);
// Replace parents placeholders in rule selector
rule.selectors = rule.selectors.map(replacePlaceholders);
// Add current selector to current parent stack
parentsStack.push(rule.selector);
// Process child rules
process(rule);
process(rule, result);
}
// Optionally replace parents placeholders into declarations
// eslint-disable-next-line brace-style
else if (opts.replaceDeclarations && rule.type === 'decl') {
rule.value = replacePlaceholders(rule.value, rule, result);
rule.prop = replacePlaceholders(rule.prop, rule, result);
}
});
// Remove current parent stack item at the end of each child iteration
parentsStack.pop();
};
return process;
return function (root, result) {
process(root, result);
};
});
{
"name": "postcss-nested-ancestors",
"version": "0.0.1",
"version": "0.1.0",
"description": "PostCSS plugin to reference any ancestor selector in nested CSS",

@@ -27,3 +27,3 @@ "keywords": [

"devDependencies": {
"ava": "^0.14.0",
"ava": "^0.16.0",
"eslint": "^2.10.0",

@@ -39,4 +39,10 @@ "eslint-config-postcss": "^2.0.2"

"eslintConfig": {
"extends": "eslint-config-postcss/es5"
"extends": "eslint-config-postcss/es5",
"rules": {
"max-len": [
"error",
90
]
}
}
}

@@ -15,3 +15,3 @@ # PostCSS Nested ancestors [![Build Status][ci-img]][ci]

**PostCSS Nested ancestors** introduce `^&` selector which let you reference **any parent ancestor selector** with an easy and customizable interface.
**PostCSS Nested ancestors** introduces `^&` selector which let you reference **any parent ancestor selector** with an easy and customizable interface.

@@ -78,3 +78,3 @@ This plugin should be used **before** a POSTCSS rules unwrapper like [postcss-nested].

[postcss-nested-ancestors] instead replaces special ancestor selectors, makes no use of variable assignment and produces an output ready to be unwrapped with [postcss-nested].
**PostCSS Nested ancestors** instead replaces special ancestor selectors, makes no use of variable assignment and produces an output ready to be unwrapped with [postcss-nested].

@@ -116,3 +116,55 @@ ## Installation

### replaceDeclarations (experimental)
Type: `boolean`
Default: `false`
If this is true then this plugin will look through your declaration values/properties for the placeholder symbol and replace them with specified selector.
An use case for this if enabling [postcss-ref](https://github.com/morishitter/postcss-ref) to work with dynamic `@ref` selectors. Read discussion [here](https://github.com/toomuchdesign/postcss-nested-ancestors/pull/3).
```css
/* Before */
.foo {
&:last-child {
border-top: ref(^&, border-bottom);
}
}
/* After PostCSS Nested ancestors and PostCSS Nested */
.foo {
}
.foo:last-child {
border-top: ref(.foo, border-bottom);
}
```
## Known issues
### Complex nesting
**PostCSS Nested ancestors** is currently not able to resolve complex nesting cases like multiple selector declarations. It might break badly.
```css
/* Before */
.foo,
.bar {
&:hover {
^&-moo {
}
}
}
/* After :-( */
.foo,
.bar {
&:hover {
.foo,.bar-moo {
}
}
}
```
## Todo's
- Add warning when nestingLevel >= parentsStack.length
* Find a smart way to resolve complex nesting issues
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