Move CSS validation helpers to separate file

wip
This commit is contained in:
Jordan Pittman 2022-05-09 16:05:04 -04:00
parent fc25299aa6
commit 3ac72b7e7d
2 changed files with 57 additions and 55 deletions

View file

@ -12,6 +12,7 @@ import { normalize } from '../util/dataTypes'
import { isValidVariantFormatString, parseVariant } from './setupContextUtils'
import isValidArbitraryValue from '../util/isValidArbitraryValue'
import { splitAtTopLevelOnly } from '../util/splitAtTopLevelOnly.js'
import { isParsableNode, isParsableCssValue, isValidPropName } from '../util/css-validation.js'
let classNameParser = selectorParser((selectors) => {
return selectors.first.filter(({ type }) => type === 'class').pop().value
@ -303,61 +304,6 @@ function parseRules(rule, cache, options = {}) {
return [cache.get(rule), options]
}
const IS_VALID_PROPERTY_NAME = /^[a-z_-]/
function isValidPropName(name) {
return IS_VALID_PROPERTY_NAME.test(name)
}
/**
* @param {string} declaration
* @returns {boolean}
*/
function looksLikeUri(declaration) {
// Quick bailout for obvious non-urls
// This doesn't support schemes that don't use a leading // but that's unlikely to be a problem
if (!declaration.includes('://')) {
return false
}
try {
const url = new URL(declaration)
return url.scheme !== '' && url.host !== ''
} catch (err) {
// Definitely not a valid url
return false
}
}
function isParsableNode(node) {
let isParsable = true
node.walkDecls((decl) => {
if (!isParsableCssValue(decl.name, decl.value)) {
isParsable = false
return false
}
})
return isParsable
}
function isParsableCssValue(property, value) {
// We don't want to to treat [https://example.com] as a custom property
// Even though, according to the CSS grammar, it's a totally valid CSS declaration
// So we short-circuit here by checking if the custom property looks like a url
if (looksLikeUri(`${property}:${value}`)) {
return false
}
try {
postcss.parse(`a{${property}:${value}}`).toResult()
return true
} catch (err) {
return false
}
}
function extractArbitraryProperty(classCandidate, context) {
let [, property, value] = classCandidate.match(/^\[([a-zA-Z0-9-_]+):(\S+)\]$/) ?? []

View file

@ -0,0 +1,56 @@
import postcss from 'postcss'
const IS_VALID_PROPERTY_NAME = /^[a-z_-]/
export function isValidPropName(name) {
return IS_VALID_PROPERTY_NAME.test(name)
}
/**
* @param {string} declaration
* @returns {boolean}
*/
export function looksLikeUri(declaration) {
// Quick bailout for obvious non-urls
// This doesn't support schemes that don't use a leading // but that's unlikely to be a problem
if (!declaration.includes('://')) {
return false
}
try {
const url = new URL(declaration)
return url.scheme !== '' && url.host !== ''
} catch (err) {
// Definitely not a valid url
return false
}
}
export function isParsableNode(node) {
let isParsable = true
node.walkDecls((decl) => {
if (!isParsableCssValue(decl.name, decl.value)) {
isParsable = false
return false
}
})
return isParsable
}
export function isParsableCssValue(property, value) {
// We don't want to to treat [https://example.com] as a custom property
// Even though, according to the CSS grammar, it's a totally valid CSS declaration
// So we short-circuit here by checking if the custom property looks like a url
if (looksLikeUri(`${property}:${value}`)) {
return false
}
try {
postcss.parse(`a{${property}:${value}}`).toResult()
return true
} catch (err) {
return false
}
}