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

postcss-modules-scope

Package Overview
Dependencies
Maintainers
3
Versions
28
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

postcss-modules-scope - npm Package Compare versions

Comparing version 2.0.1 to 2.1.0

CHANGELOG.md

16

package.json
{
"name": "postcss-modules-scope",
"version": "2.0.1",
"version": "2.1.0",
"description": "A CSS Modules transform to extract export statements from local-scope classes",

@@ -37,5 +37,10 @@ "main": "src/index.js",

"homepage": "https://github.com/css-modules/postcss-modules-scope",
"prettier": {
"semi": true,
"singleQuote": true,
"trailingComma": "es5"
},
"dependencies": {
"css-selector-tokenizer": "^0.7.0",
"postcss": "^7.0.6"
"postcss": "^7.0.6",
"postcss-selector-parser": "^6.0.0"
},

@@ -46,7 +51,6 @@ "devDependencies": {

"coveralls": "^3.0.2",
"css-selector-parser": "^1.0.4",
"eslint": "^5.9.0",
"nyc": "^13.1.0",
"mocha": "^5.2.0"
"mocha": "^6.0.2",
"nyc": "^13.1.0"
}
}
'use strict';
const postcss = require('postcss');
const Tokenizer = require('css-selector-tokenizer');
const selectorParser = require('postcss-selector-parser');
const hasOwnProperty = Object.prototype.hasOwnProperty;
function getSingleLocalNamesForComposes(selectors) {
return selectors.nodes.map(node => {
function getSingleLocalNamesForComposes(root) {
return root.nodes.map(node => {
if (node.type !== 'selector' || node.nodes.length !== 1) {
throw new Error(
'composition is only allowed when selector is single :local class name not in "' +
Tokenizer.stringify(selectors) +
'"'
`composition is only allowed when selector is single :local class name not in "${root}"`
);
}
node = node.nodes[0];
if (
node.type !== 'nested-pseudo-class' ||
node.name !== 'local' ||
node.type !== 'pseudo' ||
node.value !== ':local' ||
node.nodes.length !== 1

@@ -25,19 +25,23 @@ ) {

'composition is only allowed when selector is single :local class name not in "' +
Tokenizer.stringify(selectors) +
root +
'", "' +
Tokenizer.stringify(node) +
node +
'" is weird'
);
}
node = node.nodes[0];
if (node.type !== 'selector' || node.nodes.length !== 1) {
node = node.first;
if (node.type !== 'selector' || node.length !== 1) {
throw new Error(
'composition is only allowed when selector is single :local class name not in "' +
Tokenizer.stringify(selectors) +
root +
'", "' +
Tokenizer.stringify(node) +
node +
'" is weird'
);
}
node = node.nodes[0];
node = node.first;
if (node.type !== 'class') {

@@ -47,12 +51,35 @@ // 'id' is not possible, because you can't compose ids

'composition is only allowed when selector is single :local class name not in "' +
Tokenizer.stringify(selectors) +
root +
'", "' +
Tokenizer.stringify(node) +
node +
'" is weird'
);
}
return node.name;
return node.value;
});
}
const whitespace = '[\\x20\\t\\r\\n\\f]';
const unescapeRegExp = new RegExp(
'\\\\([\\da-f]{1,6}' + whitespace + '?|(' + whitespace + ')|.)',
'ig'
);
function unescape(str) {
return str.replace(unescapeRegExp, (_, escaped, escapedWhitespace) => {
const high = '0x' + escaped - 0x10000;
// NaN means non-codepoint
// Workaround erroneous numeric interpretation of +"0x"
return high !== high || escapedWhitespace
? escaped
: high < 0
? // BMP codepoint
String.fromCharCode(high + 0x10000)
: // Supplemental Plane codepoint (surrogate pair)
String.fromCharCode((high >> 10) | 0xd800, (high & 0x3ff) | 0xdc00);
});
}
const processor = postcss.plugin('postcss-modules-scope', function(options) {

@@ -62,15 +89,27 @@ return css => {

(options && options.generateScopedName) || processor.generateScopedName;
const generateExportEntry =
(options && options.generateExportEntry) || processor.generateExportEntry;
const exports = Object.create(null);
function exportScopedName(name) {
function exportScopedName(name, rawName) {
const scopedName = generateScopedName(
name,
rawName ? rawName : name,
css.source.input.from,
css.source.input.css
);
exports[name] = exports[name] || [];
if (exports[name].indexOf(scopedName) < 0) {
exports[name].push(scopedName);
const exportEntry = generateExportEntry(
rawName ? rawName : name,
scopedName,
css.source.input.from,
css.source.input.css
);
const { key, value } = exportEntry;
exports[key] = exports[key] || [];
if (exports[key].indexOf(value) < 0) {
exports[key].push(value);
}
return scopedName;

@@ -80,18 +119,25 @@ }

function localizeNode(node) {
const newNode = Object.create(node);
switch (node.type) {
case 'selector':
newNode.nodes = node.nodes.map(localizeNode);
return newNode;
node.nodes = node.map(localizeNode);
return node;
case 'class':
return selectorParser.className({
value: exportScopedName(
node.value,
node.raws && node.raws.value ? node.raws.value : null
),
});
case 'id': {
newNode.name = exportScopedName(node.name);
return newNode;
return selectorParser.id({
value: exportScopedName(
node.value,
node.raws && node.raws.value ? node.raws.value : null
),
});
}
}
throw new Error(
node.type +
' ("' +
Tokenizer.stringify(node) +
'") is not allowed in a :local block'
`${node.type} ("${node}") is not allowed in a :local block`
);

@@ -102,15 +148,22 @@ }

switch (node.type) {
case 'nested-pseudo-class':
if (node.name === 'local') {
case 'pseudo':
if (node.value === ':local') {
if (node.nodes.length !== 1) {
throw new Error('Unexpected comma (",") in :local block');
}
return localizeNode(node.nodes[0]);
const selector = localizeNode(node.first, node.spaces);
// move the spaces that were around the psuedo selector to the first
// non-container node
selector.first.spaces = node.spaces;
node.replaceWith(selector);
return;
}
/* falls through */
case 'selectors':
case 'root':
case 'selector': {
const newNode = Object.create(node);
newNode.nodes = node.nodes.map(traverseNode);
return newNode;
node.each(traverseNode);
break;
}

@@ -123,2 +176,3 @@ }

const importedNames = {};
css.walkRules(rule => {

@@ -134,10 +188,22 @@ if (/^:import\(.+\)$/.test(rule.selector)) {

css.walkRules(rule => {
const selector = Tokenizer.parse(rule.selector);
const newSelector = traverseNode(selector);
rule.selector = Tokenizer.stringify(newSelector);
if (
rule.nodes &&
rule.selector.slice(0, 2) === '--' &&
rule.selector.slice(-1) === ':'
) {
// ignore custom property set
return;
}
let parsedSelector = selectorParser().astSync(rule);
rule.selector = traverseNode(parsedSelector.clone()).toString();
rule.walkDecls(/composes|compose-with/, decl => {
const localNames = getSingleLocalNamesForComposes(selector);
const localNames = getSingleLocalNamesForComposes(parsedSelector);
const classes = decl.value.split(/\s+/);
classes.forEach(className => {
const global = /^global\(([^\)]+)\)$/.exec(className);
if (global) {

@@ -163,2 +229,3 @@ localNames.forEach(exportedName => {

});
decl.remove();

@@ -168,6 +235,8 @@ });

rule.walkDecls(decl => {
var tokens = decl.value.split(/(,|'[^']*'|"[^"]*")/);
let tokens = decl.value.split(/(,|'[^']*'|"[^"]*")/);
tokens = tokens.map((token, idx) => {
if (idx === 0 || tokens[idx - 1] === ',') {
const localMatch = /^(\s*):local\s*\((.+?)\)/.exec(token);
if (localMatch) {

@@ -186,2 +255,3 @@ return (

});
decl.value = tokens.join('');

@@ -194,3 +264,4 @@ });

if (/keyframes$/i.test(atrule.name)) {
var localMatch = /^\s*:local\s*\((.+?)\)\s*$/.exec(atrule.params);
const localMatch = /^\s*:local\s*\((.+?)\)\s*$/.exec(atrule.params);
if (localMatch) {

@@ -204,4 +275,6 @@ atrule.params = exportScopedName(localMatch[1]);

const exportedNames = Object.keys(exports);
if (exportedNames.length > 0) {
const exportRule = postcss.rule({ selector: ':export' });
exportedNames.forEach(exportedName =>

@@ -211,5 +284,6 @@ exportRule.append({

value: exports[exportedName].join(' '),
raws: { before: '\n ' }
raws: { before: '\n ' },
})
);
css.append(exportRule);

@@ -220,3 +294,3 @@ }

processor.generateScopedName = function(exportedName, path) {
processor.generateScopedName = function(name, path) {
const sanitisedPath = path

@@ -226,5 +300,13 @@ .replace(/\.[^\.\/\\]+$/, '')

.replace(/^_|_$/g, '');
return `_${sanitisedPath}__${exportedName}`;
return `_${sanitisedPath}__${name}`.trim();
};
processor.generateExportEntry = function(name, scopedName) {
return {
key: unescape(name),
value: unescape(scopedName),
};
};
module.exports = processor;
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