feat: refactoring project

This commit is contained in:
Carlos
2024-11-23 14:56:07 -05:00
parent f0c2a50c18
commit 1c6db5818d
2351 changed files with 39323 additions and 60326 deletions

View File

@@ -4,6 +4,8 @@
Transformation examples:
Selectors (mode `local`, by default)::
<!-- prettier-ignore-start -->
```css
.foo { ... } /* => */ :local(.foo) { ... }
@@ -28,6 +30,45 @@ Transformation examples:
```
<!-- prettier-ignore-end -->
Declarations (mode `local`, by default):
<!-- prettier-ignore-start -->
```css
.foo {
animation-name: fadeInOut, global(moveLeft300px), local(bounce);
}
.bar {
animation: rotate 1s, global(spin) 3s, local(fly) 6s;
}
/* => */
:local(.foo) {
animation-name: :local(fadeInOut), moveLeft300px, :local(bounce);
}
:local(.bar) {
animation: :local(rotate) 1s, spin 3s, :local(fly) 6s;
}
```
<!-- prettier-ignore-end -->
## Pure Mode
In pure mode, all selectors must contain at least one local class or id
selector
To ignore this rule for a specific selector, add the following comment in front
of the selector:
```css
/* cssmodules-pure-ignore */
:global(#modal-backdrop) {
...;
}
```
## Building
```bash

View File

@@ -1,6 +1,6 @@
{
"name": "postcss-modules-local-by-default",
"version": "4.0.5",
"version": "4.1.0",
"description": "A CSS Modules transform to make local scope the default",
"main": "src/index.js",
"author": "Mark Dalgleish",
@@ -33,7 +33,7 @@
},
"dependencies": {
"icss-utils": "^5.0.0",
"postcss-selector-parser": "^6.0.2",
"postcss-selector-parser": "^7.0.0",
"postcss-value-parser": "^4.1.0"
},
"devDependencies": {

View File

@@ -4,8 +4,29 @@ const selectorParser = require("postcss-selector-parser");
const valueParser = require("postcss-value-parser");
const { extractICSS } = require("icss-utils");
const IGNORE_MARKER = "cssmodules-pure-ignore";
const isSpacing = (node) => node.type === "combinator" && node.value === " ";
function getIgnoreComment(node) {
if (!node.parent) {
return;
}
const indexInParent = node.parent.index(node);
for (let i = indexInParent - 1; i >= 0; i--) {
const prevNode = node.parent.nodes[i];
if (prevNode.type === "comment") {
if (prevNode.text.trimStart().startsWith(IGNORE_MARKER)) {
return prevNode;
}
} else {
break;
}
}
}
function normalizeNodeArray(nodes) {
const array = [];
@@ -25,6 +46,8 @@ function normalizeNodeArray(nodes) {
return array;
}
const isPureSelectorSymbol = Symbol("is-pure-selector");
function localizeNode(rule, mode, localAliasMap) {
const transform = (node, context) => {
if (context.ignoreNextSpacing && !isSpacing(node)) {
@@ -232,7 +255,7 @@ function localizeNode(rule, mode, localAliasMap) {
}
case "nesting": {
if (node.value === "&") {
context.hasLocals = true;
context.hasLocals = rule.parent[isPureSelectorSymbol];
}
}
}
@@ -347,24 +370,20 @@ function localizeDeclarationValues(localize, declaration, context) {
declaration.value = valueNodes.toString();
}
function localizeDeclaration(declaration, context) {
const isAnimation = /animation$/i.test(declaration.prop);
// letter
// An uppercase letter or a lowercase letter.
//
// ident-start code point
// A letter, a non-ASCII code point, or U+005F LOW LINE (_).
//
// ident code point
// An ident-start code point, a digit, or U+002D HYPHEN-MINUS (-).
if (isAnimation) {
// letter
// An uppercase letter or a lowercase letter.
//
// ident-start code point
// A letter, a non-ASCII code point, or U+005F LOW LINE (_).
//
// ident code point
// An ident-start code point, a digit, or U+002D HYPHEN-MINUS (-).
// We don't validate `hex digits`, because we don't need it, it is work of linters.
const validIdent =
/^-?([a-z\u0080-\uFFFF_]|(\\[^\r\n\f])|-(?![0-9]))((\\[^\r\n\f])|[a-z\u0080-\uFFFF_0-9-])*$/i;
// We don't validate `hex digits`, because we don't need it, it is work of linters.
const validIdent =
/^-?([a-z\u0080-\uFFFF_]|(\\[^\r\n\f])|-(?![0-9]))((\\[^\r\n\f])|[a-z\u0080-\uFFFF_0-9-])*$/i;
/*
/*
The spec defines some keywords that you can use to describe properties such as the timing
function. These are still valid animation names, so as long as there is a property that accepts
a keyword, it is given priority. Only when all the properties that can take a keyword are
@@ -375,38 +394,43 @@ function localizeDeclaration(declaration, context) {
The animation will repeat an infinite number of times from the first argument, and will have an
animation name of infinite from the second.
*/
const animationKeywords = {
// animation-direction
$normal: 1,
$reverse: 1,
$alternate: 1,
"$alternate-reverse": 1,
// animation-fill-mode
$forwards: 1,
$backwards: 1,
$both: 1,
// animation-iteration-count
$infinite: 1,
// animation-play-state
$paused: 1,
$running: 1,
// animation-timing-function
$ease: 1,
"$ease-in": 1,
"$ease-out": 1,
"$ease-in-out": 1,
$linear: 1,
"$step-end": 1,
"$step-start": 1,
// Special
$none: Infinity, // No matter how many times you write none, it will never be an animation name
// Global values
$initial: Infinity,
$inherit: Infinity,
$unset: Infinity,
$revert: Infinity,
"$revert-layer": Infinity,
};
const animationKeywords = {
// animation-direction
$normal: 1,
$reverse: 1,
$alternate: 1,
"$alternate-reverse": 1,
// animation-fill-mode
$forwards: 1,
$backwards: 1,
$both: 1,
// animation-iteration-count
$infinite: 1,
// animation-play-state
$paused: 1,
$running: 1,
// animation-timing-function
$ease: 1,
"$ease-in": 1,
"$ease-out": 1,
"$ease-in-out": 1,
$linear: 1,
"$step-end": 1,
"$step-start": 1,
// Special
$none: Infinity, // No matter how many times you write none, it will never be an animation name
// Global values
$initial: Infinity,
$inherit: Infinity,
$unset: Infinity,
$revert: Infinity,
"$revert-layer": Infinity,
};
function localizeDeclaration(declaration, context) {
const isAnimation = /animation(-name)?$/i.test(declaration.prop);
if (isAnimation) {
let parsedAnimationKeywords = {};
const valueNodes = valueParser(declaration.value).walk((node) => {
// If div-token appeared (represents as comma ','), a possibility of an animation-keywords should be reflesh.
@@ -414,9 +438,28 @@ function localizeDeclaration(declaration, context) {
parsedAnimationKeywords = {};
return;
}
// Do not handle nested functions
else if (node.type === "function") {
} else if (
node.type === "function" &&
node.value.toLowerCase() === "local" &&
node.nodes.length === 1
) {
node.type = "word";
node.value = node.nodes[0].value;
return localizeDeclNode(node, {
options: context.options,
global: context.global,
localizeNextItem: true,
localAliasMap: context.localAliasMap,
});
} else if (node.type === "function") {
// replace `animation: global(example)` with `animation-name: example`
if (node.value.toLowerCase() === "global" && node.nodes.length === 1) {
node.type = "word";
node.value = node.nodes[0].value;
}
// Do not handle nested functions
return false;
}
// Ignore all except word
@@ -443,14 +486,12 @@ function localizeDeclaration(declaration, context) {
}
}
const subContext = {
return localizeDeclNode(node, {
options: context.options,
global: context.global,
localizeNextItem: shouldParseAnimationName && !context.global,
localAliasMap: context.localAliasMap,
};
return localizeDeclNode(node, subContext);
});
});
declaration.value = valueNodes.toString();
@@ -458,19 +499,35 @@ function localizeDeclaration(declaration, context) {
return;
}
const isAnimationName = /animation(-name)?$/i.test(declaration.prop);
if (isAnimationName) {
return localizeDeclarationValues(true, declaration, context);
}
const hasUrl = /url\(/i.test(declaration.value);
if (hasUrl) {
if (/url\(/i.test(declaration.value)) {
return localizeDeclarationValues(false, declaration, context);
}
}
const isPureSelector = (context, rule) => {
if (!rule.parent || rule.type === "root") {
return !context.hasPureGlobals;
}
if (rule.type === "rule" && rule[isPureSelectorSymbol]) {
return rule[isPureSelectorSymbol] || isPureSelector(context, rule.parent);
}
return !context.hasPureGlobals || isPureSelector(context, rule.parent);
};
const isNodeWithoutDeclarations = (rule) => {
if (rule.nodes.length > 0) {
return !rule.nodes.every(
(item) =>
item.type === "rule" ||
(item.type === "atrule" && !isNodeWithoutDeclarations(item))
);
}
return true;
};
module.exports = (options = {}) => {
if (
options &&
@@ -515,10 +572,17 @@ module.exports = (options = {}) => {
if (globalMatch) {
if (pureMode) {
throw atRule.error(
"@keyframes :global(...) is not allowed in pure mode"
);
const ignoreComment = getIgnoreComment(atRule);
if (!ignoreComment) {
throw atRule.error(
"@keyframes :global(...) is not allowed in pure mode"
);
} else {
ignoreComment.remove();
}
}
atRule.params = globalMatch[1];
globalKeyframes = true;
} else if (localMatch) {
@@ -541,6 +605,14 @@ module.exports = (options = {}) => {
});
} else if (/scope$/i.test(atRule.name)) {
if (atRule.params) {
const ignoreComment = pureMode
? getIgnoreComment(atRule)
: undefined;
if (ignoreComment) {
ignoreComment.remove();
}
atRule.params = atRule.params
.split("to")
.map((item) => {
@@ -554,7 +626,7 @@ module.exports = (options = {}) => {
context.options = options;
context.localAliasMap = localAliasMap;
if (pureMode && context.hasPureGlobals) {
if (pureMode && context.hasPureGlobals && !ignoreComment) {
throw atRule.error(
'Selector in at-rule"' +
selector +
@@ -605,13 +677,26 @@ module.exports = (options = {}) => {
context.options = options;
context.localAliasMap = localAliasMap;
if (pureMode && context.hasPureGlobals) {
const ignoreComment = pureMode ? getIgnoreComment(rule) : undefined;
const isNotPure = pureMode && !isPureSelector(context, rule);
if (
isNotPure &&
isNodeWithoutDeclarations(rule) &&
!ignoreComment
) {
throw rule.error(
'Selector "' +
rule.selector +
'" is not pure ' +
"(pure selectors must contain at least one local class or id)"
);
} else if (ignoreComment) {
ignoreComment.remove();
}
if (pureMode) {
rule[isPureSelectorSymbol] = !isNotPure;
}
rule.selector = context.selector;