-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
238 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import hasLessInterpolation from './hasLessInterpolation.mjs'; | ||
import hasPsvInterpolation from './hasPsvInterpolation.mjs'; | ||
import hasScssInterpolation from './hasScssInterpolation.mjs'; | ||
import hasTplInterpolation from './hasTplInterpolation.mjs'; | ||
|
||
/** | ||
* Check whether a string has interpolation | ||
* | ||
* @param {string} string | ||
* @return {boolean} If `true`, a string has interpolation | ||
*/ | ||
export default function hasInterpolation(string) { | ||
// SCSS or Less interpolation | ||
if ( | ||
hasLessInterpolation(string) || | ||
hasScssInterpolation(string) || | ||
hasTplInterpolation(string) || | ||
hasPsvInterpolation(string) | ||
) { | ||
return true; | ||
} | ||
|
||
return false; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
const HAS_LESS_INTERPOLATION = /@\{.+?\}/; | ||
|
||
/** | ||
* Check whether a string has less interpolation | ||
* | ||
* @param {string} string | ||
* @return {boolean} If `true`, a string has less interpolation | ||
*/ | ||
export default function hasLessInterpolation(string) { | ||
return HAS_LESS_INTERPOLATION.test(string); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
const HAS_PSV_INTERPOLATION = /\$\(.+?\)/; | ||
|
||
/** | ||
* Check whether a string has postcss-simple-vars interpolation | ||
* | ||
* @param {string} string | ||
* @returns {boolean} | ||
*/ | ||
export default function hasPsvInterpolation(string) { | ||
return HAS_PSV_INTERPOLATION.test(string); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
const HAS_SCSS_INTERPOLATION = /#\{.+?\}/s; | ||
|
||
/** | ||
* Check whether a string has scss interpolation | ||
* | ||
* @param {string} string | ||
* @returns {boolean} | ||
*/ | ||
export default function hasScssInterpolation(string) { | ||
return HAS_SCSS_INTERPOLATION.test(string); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
const HAS_TPL_INTERPOLATION = /\{.+?\}/s; | ||
|
||
/** | ||
* Check whether a string has JS template literal interpolation or HTML-like template | ||
* | ||
* @param {string} string | ||
* @return {boolean} If `true`, a string has template literal interpolation | ||
*/ | ||
export default function hasTplInterpolation(string) { | ||
return HAS_TPL_INTERPOLATION.test(string); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import isStandardSyntaxSelector from './isStandardSyntaxSelector.mjs'; | ||
|
||
/** | ||
* Check whether a Node is a standard rule | ||
* | ||
* @param {import('postcss').Rule | import('postcss-less').Rule} rule | ||
* @returns {boolean} | ||
*/ | ||
export default function isStandardSyntaxRule(rule) { | ||
if (rule.type !== 'rule') { | ||
return false; | ||
} | ||
|
||
// Ignore Less &:extend rule | ||
if ('extend' in rule && rule.extend) { | ||
return false; | ||
} | ||
|
||
if (!isStandardSyntaxSelector(rule.selector)) { | ||
return false; | ||
} | ||
|
||
return true; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import hasInterpolation from './hasInterpolation.mjs'; | ||
|
||
/** | ||
* Check whether a selector is standard | ||
* | ||
* @param {string} selector | ||
* @returns {boolean} | ||
*/ | ||
export default function isStandardSyntaxSelector(selector) { | ||
// SCSS or Less interpolation | ||
if (hasInterpolation(selector)) { | ||
return false; | ||
} | ||
|
||
// SCSS placeholder selectors | ||
if (selector.startsWith('%')) { | ||
return false; | ||
} | ||
|
||
// SCSS nested properties | ||
if (selector.endsWith(':')) { | ||
return false; | ||
} | ||
|
||
// Less :extend() | ||
if (/:extend(?:\(.*?\))?/.test(selector)) { | ||
return false; | ||
} | ||
|
||
// Less mixin with resolved nested selectors (e.g. .foo().bar or .foo(@a, @b)[bar]) | ||
if (/\.[\w-]+\(.*\).+/.test(selector)) { | ||
return false; | ||
} | ||
|
||
// Less non-outputting mixin definition (e.g. .mixin() {}) | ||
if (selector.endsWith(')') && !selector.includes(':')) { | ||
return false; | ||
} | ||
|
||
// Less Parametric mixins (e.g. .mixin(@variable: x) {}) | ||
if (/\(@.*\)$/.test(selector)) { | ||
return false; | ||
} | ||
|
||
// ERB template tags | ||
if (selector.includes('<%') || selector.includes('%>')) { | ||
return false; | ||
} | ||
|
||
// SCSS and Less comments | ||
if (selector.includes('//')) { | ||
return false; | ||
} | ||
|
||
return true; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
/** | ||
* Compares a string to a second value that, if it fits a certain convention, | ||
* is converted to a regular expression before the comparison. | ||
* If it doesn't fit the convention, then two strings are compared. | ||
* | ||
* Any strings starting and ending with `/` are interpreted | ||
* as regular expressions. | ||
* | ||
* @param {string | Array<string>} input | ||
* @param {string | RegExp | Array<string | RegExp>} comparison | ||
* | ||
* @returns {false | {match: string, pattern: (string | RegExp), substring: string}} | ||
*/ | ||
export default function matchesStringOrRegExp(input, comparison) { | ||
if (!Array.isArray(input)) { | ||
return testAgainstStringOrRegExpOrArray(input, comparison); | ||
} | ||
|
||
for (const inputItem of input) { | ||
const testResult = testAgainstStringOrRegExpOrArray(inputItem, comparison); | ||
|
||
if (testResult) { | ||
return testResult; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
/** | ||
* @param {string} value | ||
* @param {string | RegExp | Array<string | RegExp>} comparison | ||
*/ | ||
function testAgainstStringOrRegExpOrArray(value, comparison) { | ||
if (!Array.isArray(comparison)) { | ||
return testAgainstStringOrRegExp(value, comparison); | ||
} | ||
|
||
for (const comparisonItem of comparison) { | ||
const testResult = testAgainstStringOrRegExp(value, comparisonItem); | ||
|
||
if (testResult) { | ||
return testResult; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
/** | ||
* @param {string} value | ||
* @param {string | RegExp} comparison | ||
*/ | ||
function testAgainstStringOrRegExp(value, comparison) { | ||
// If it's a RegExp, test directly | ||
if (comparison instanceof RegExp) { | ||
const match = value.match(comparison); | ||
|
||
return match ? { match: value, pattern: comparison, substring: match[0] || '' } : false; | ||
} | ||
|
||
// Check if it's RegExp in a string | ||
const firstComparisonChar = comparison[0]; | ||
const lastComparisonChar = comparison[comparison.length - 1]; | ||
const secondToLastComparisonChar = comparison[comparison.length - 2]; | ||
|
||
const comparisonIsRegex = | ||
firstComparisonChar === '/' && | ||
(lastComparisonChar === '/' || | ||
(secondToLastComparisonChar === '/' && lastComparisonChar === 'i')); | ||
|
||
const hasCaseInsensitiveFlag = comparisonIsRegex && lastComparisonChar === 'i'; | ||
|
||
// If so, create a new RegExp from it | ||
if (comparisonIsRegex) { | ||
const valueMatch = hasCaseInsensitiveFlag | ||
? value.match(new RegExp(comparison.slice(1, -2), 'i')) | ||
: value.match(new RegExp(comparison.slice(1, -1))); | ||
|
||
return valueMatch | ||
? { match: value, pattern: comparison, substring: valueMatch[0] || '' } | ||
: false; | ||
} | ||
|
||
// Otherwise, it's a string. Do a strict comparison | ||
return value === comparison ? { match: value, pattern: comparison, substring: value } : false; | ||
} |