@tbela99/css-parser
Version:
CSS parser for node and the browser
816 lines (806 loc) • 28.3 kB
JavaScript
import { colorsFunc } from '../renderer/render.js';
import { EnumToken } from '../ast/types.js';
import '../ast/minify.js';
import '../ast/walk.js';
import '../parser/parse.js';
import '../parser/utils/config.js';
import { COLORS_NAMES } from '../renderer/color/utils/constants.js';
// https://www.w3.org/TR/CSS21/syndata.html#syntax
// https://www.w3.org/TR/2021/CRD-css-syntax-3-20211224/#typedef-ident-token
// '\\'
const REVERSE_SOLIDUS = 0x5c;
const dimensionUnits = new Set([
'q', 'cap', 'ch', 'cm', 'cqb', 'cqh', 'cqi', 'cqmax', 'cqmin', 'cqw', 'dvb',
'dvh', 'dvi', 'dvmax', 'dvmin', 'dvw', 'em', 'ex', 'ic', 'in', 'lh', 'lvb',
'lvh', 'lvi', 'lvmax', 'lvw', 'mm', 'pc', 'pt', 'px', 'rem', 'rlh', 'svb',
'svh', 'svi', 'svmin', 'svw', 'vb', 'vh', 'vi', 'vmax', 'vmin', 'vw'
]);
const fontFormat = ['collection', 'embedded-opentype', 'opentype', 'svg', 'truetype', 'woff', 'woff2'];
const colorFontTech = ['color-colrv0', 'color-colrv1', 'color-svg', 'color-sbix', 'color-cbdt'];
const fontFeaturesTech = ['features-opentype', 'features-aat', 'features-graphite', 'incremental-patch', 'incremental-range', 'incremental-auto', 'variations', 'palettes'];
// https://drafts.csswg.org/mediaqueries/#media-types
const mediaTypes = ['all', 'print', 'screen',
/* deprecated */
'aural', 'braille', 'embossed', 'handheld', 'projection', 'tty', 'tv', 'speech'];
// https://www.w3.org/TR/css-values-4/#math-function
const mathFuncs = ['calc', 'clamp', 'min', 'max', 'round', 'mod', 'rem', 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'atan2', 'pow', 'sqrt', 'hypot', 'log', 'exp', 'abs', 'sign'];
const pseudoElements = [':before', ':after', ':first-line', ':first-letter'];
const webkitPseudoAliasMap = {
'-webkit-autofill': 'autofill',
'-webkit-any': 'is',
'-moz-any': 'is',
'-webkit-border-after': 'border-block-end',
'-webkit-border-after-color': 'border-block-end-color',
'-webkit-border-after-style': 'border-block-end-style',
'-webkit-border-after-width': 'border-block-end-width',
'-webkit-border-before': 'border-block-start',
'-webkit-border-before-color': 'border-block-start-color',
'-webkit-border-before-style': 'border-block-start-style',
'-webkit-border-before-width': 'border-block-start-width',
'-webkit-border-end': 'border-inline-end',
'-webkit-border-end-color': 'border-inline-end-color',
'-webkit-border-end-style': 'border-inline-end-style',
'-webkit-border-end-width': 'border-inline-end-width',
'-webkit-border-start': 'border-inline-start',
'-webkit-border-start-color': 'border-inline-start-color',
'-webkit-border-start-style': 'border-inline-start-style',
'-webkit-border-start-width': 'border-inline-start-width',
'-webkit-box-align': 'align-items',
'-webkit-box-direction': 'flex-direction',
'-webkit-box-flex': 'flex-grow',
'-webkit-box-lines': 'flex-flow',
'-webkit-box-ordinal-group': 'order',
'-webkit-box-orient': 'flex-direction',
'-webkit-box-pack': 'justify-content',
'-webkit-column-break-after': 'break-after',
'-webkit-column-break-before': 'break-before',
'-webkit-column-break-inside': 'break-inside',
'-webkit-font-feature-settings': 'font-feature-settings',
'-webkit-hyphenate-character': 'hyphenate-character',
'-webkit-initial-letter': 'initial-letter',
'-webkit-margin-end': 'margin-block-end',
'-webkit-margin-start': 'margin-block-start',
'-webkit-padding-after': 'padding-block-end',
'-webkit-padding-before': 'padding-block-start',
'-webkit-padding-end': 'padding-inline-end',
'-webkit-padding-start': 'padding-inline-start',
'-webkit-min-device-pixel-ratio': 'min-resolution',
'-webkit-max-device-pixel-ratio': 'max-resolution'
};
// https://developer.mozilla.org/en-US/docs/Web/CSS/WebKit_Extensions
// https://developer.mozilla.org/en-US/docs/Web/CSS/::-webkit-scrollbar
const webkitExtensions = new Set([
'-webkit-app-region',
'-webkit-border-horizontal-spacing',
'-webkit-border-vertical-spacing',
'-webkit-box-reflect',
'-webkit-column-axis',
'-webkit-column-progression',
'-webkit-cursor-visibility',
'-webkit-font-smoothing',
'-webkit-hyphenate-limit-after',
'-webkit-hyphenate-limit-before',
'-webkit-hyphenate-limit-lines',
'-webkit-line-align',
'-webkit-line-box-contain',
'-webkit-line-clamp',
'-webkit-line-grid',
'-webkit-line-snap',
'-webkit-locale',
'-webkit-logical-height',
'-webkit-logical-width',
'-webkit-margin-after',
'-webkit-margin-before',
'-webkit-mask-box-image-outset',
'-webkit-mask-box-image-repeat',
'-webkit-mask-box-image-slice',
'-webkit-mask-box-image-source',
'-webkit-mask-box-image-width',
'-webkit-mask-box-image',
'-webkit-mask-composite',
'-webkit-mask-position-x',
'-webkit-mask-position-y',
'-webkit-mask-repeat-x',
'-webkit-mask-repeat-y',
'-webkit-mask-source-type',
'-webkit-max-logical-height',
'-webkit-max-logical-width',
'-webkit-min-logical-height',
'-webkit-min-logical-width',
'-webkit-nbsp-mode',
'-webkit-perspective-origin-x',
'-webkit-perspective-origin-y',
'-webkit-rtl-ordering',
'-webkit-tap-highlight-color',
'-webkit-text-decoration-skip',
'-webkit-text-decorations-in-effect',
'-webkit-text-fill-color',
'-webkit-text-security',
'-webkit-text-stroke-color',
'-webkit-text-stroke-width',
'-webkit-text-stroke',
'-webkit-text-zoom',
'-webkit-touch-callout',
'-webkit-transform-origin-x',
'-webkit-transform-origin-y',
'-webkit-transform-origin-z',
'-webkit-user-drag',
'-webkit-user-modify',
'-webkit-border-after',
'-webkit-border-after-color',
'-webkit-border-after-style',
'-webkit-border-after-width',
'-webkit-border-before',
'-webkit-border-before-color',
'-webkit-border-before-style',
'-webkit-border-before-width',
'-webkit-border-end',
'-webkit-border-end-color',
'-webkit-border-end-style',
'-webkit-border-end-width',
'-webkit-border-start',
'-webkit-border-start-color',
'-webkit-border-start-style',
'-webkit-border-start-width',
'-webkit-box-align',
'-webkit-box-direction',
'-webkit-box-flex-group',
'-webkit-box-flex',
'-webkit-box-lines',
'-webkit-box-ordinal-group',
'-webkit-box-orient',
'-webkit-box-pack',
'-webkit-column-break-after',
'-webkit-column-break-before',
'-webkit-column-break-inside',
'-webkit-font-feature-settings',
'-webkit-hyphenate-character',
'-webkit-initial-letter',
'-webkit-margin-end',
'-webkit-margin-start',
'-webkit-padding-after',
'-webkit-padding-before',
'-webkit-padding-end',
'-webkit-padding-start',
'-webkit-fill-available',
':-webkit-animating-full-screen-transition',
':-webkit-any',
':-webkit-any-link',
':-webkit-autofill',
':-webkit-autofill-strong-password',
':-webkit-drag',
':-webkit-full-page-media',
':-webkit-full-screen*',
':-webkit-full-screen-ancestor',
':-webkit-full-screen-document',
':-webkit-full-screen-controls-hidden',
'::-webkit-file-upload-button*',
'::-webkit-inner-spin-button',
'::-webkit-input-placeholder',
'::-webkit-meter-bar',
'::-webkit-meter-even-less-good-value',
'::-webkit-meter-inner-element',
'::-webkit-meter-optimum-value',
'::-webkit-meter-suboptimum-value',
'::-webkit-progress-bar',
'::-webkit-progress-inner-element',
'::-webkit-progress-value',
'::-webkit-search-cancel-button',
'::-webkit-search-results-button',
'::-webkit-slider-runnable-track',
'::-webkit-slider-thumb',
'-webkit-animation',
'-webkit-device-pixel-ratio',
'-webkit-transform-2d',
'-webkit-transform-3d',
'-webkit-transition',
'::-webkit-scrollbar',
'::-webkit-scrollbar-button',
'::-webkit-scrollbar',
'::-webkit-scrollbar-thumb',
'::-webkit-scrollbar-track',
'::-webkit-scrollbar-track-piece',
'::-webkit-scrollbar:vertical',
'::-webkit-scrollbar-corner ',
'::-webkit-resizer',
':vertical',
':horizontal',
]);
// https://developer.mozilla.org/en-US/docs/Web/CSS/Mozilla_Extensions
const mozExtensions = new Set([
'-moz-box-align',
'-moz-box-direction',
'-moz-box-flex',
'-moz-box-ordinal-group',
'-moz-box-orient',
'-moz-box-pack',
'-moz-float-edge',
'-moz-force-broken-image-icon',
'-moz-image-region',
'-moz-orient',
'-moz-osx-font-smoothing',
'-moz-user-focus',
'-moz-user-input',
'-moz-user-modify',
'-moz-animation',
'-moz-animation-delay',
'-moz-animation-direction',
'-moz-animation-duration',
'-moz-animation-fill-mode',
'-moz-animation-iteration-count',
'-moz-animation-name',
'-moz-animation-play-state',
'-moz-animation-timing-function',
'-moz-appearance',
'-moz-backface-visibility',
'-moz-background-clip',
'-moz-background-origin',
'-moz-background-inline-policy',
'-moz-background-size',
'-moz-border-end',
'-moz-border-end-color',
'-moz-border-end-style',
'-moz-border-end-width',
'-moz-border-image',
'-moz-border-start',
'-moz-border-start-color',
'-moz-border-start-style',
'-moz-border-start-width',
'-moz-box-sizing',
'clip-path',
'-moz-column-count',
'-moz-column-fill',
'-moz-column-gap',
'-moz-column-width',
'-moz-column-rule',
'-moz-column-rule-width',
'-moz-column-rule-style',
'-moz-column-rule-color',
'filter',
'-moz-font-feature-settings',
'-moz-font-language-override',
'-moz-hyphens',
'-moz-margin-end',
'-moz-margin-start',
'mask',
'-moz-opacity',
'-moz-outline',
'-moz-outline-color',
'-moz-outline-offset',
'-moz-outline-style',
'-moz-outline-width',
'-moz-padding-end',
'-moz-padding-start',
'-moz-perspective',
'-moz-perspective-origin',
'pointer-events',
'-moz-tab-size',
'-moz-text-align-last',
'-moz-text-decoration-color',
'-moz-text-decoration-line',
'-moz-text-decoration-style',
'-moz-text-size-adjust',
'-moz-transform',
'-moz-transform-origin',
'-moz-transform-style',
'-moz-transition',
'-moz-transition-delay',
'-moz-transition-duration',
'-moz-transition-property',
'-moz-transition-timing-function',
'-moz-user-select',
'-moz-initial',
'-moz-appearance',
'-moz-linear-gradient',
'-moz-radial-gradient',
'-moz-element',
'-moz-image-rect',
'::-moz-anonymous-block',
'::-moz-anonymous-positioned-block',
':-moz-any',
':-moz-any-link',
':-moz-broken',
'::-moz-canvas',
'::-moz-color-swatch',
'::-moz-cell-content',
':-moz-drag-over',
':-moz-first-node',
'::-moz-focus-inner',
'::-moz-focus-outer',
':-moz-full-screen',
':-moz-full-screen-ancestor',
':-moz-handler-blocked',
':-moz-handler-crashed',
':-moz-handler-disabled',
'::-moz-inline-table',
':-moz-last-node',
'::-moz-list-bullet',
'::-moz-list-number',
':-moz-loading',
':-moz-locale-dir',
':-moz-locale-dir',
':-moz-lwtheme',
':-moz-lwtheme-brighttext',
':-moz-lwtheme-darktext',
'::-moz-meter-bar',
':-moz-native-anonymous',
':-moz-only-whitespace',
'::-moz-pagebreak',
'::-moz-pagecontent',
':-moz-placeholder',
'::-moz-placeholder',
'::-moz-progress-bar',
'::-moz-range-progress',
'::-moz-range-thumb',
'::-moz-range-track',
':-moz-read-only',
':-moz-read-write',
'::-moz-scrolled-canvas',
'::-moz-scrolled-content',
'::-moz-selection',
':-moz-submit-invalid',
':-moz-suppressed',
'::-moz-svg-foreign-content',
'::-moz-table',
'::-moz-table-cell',
'::-moz-table-column',
'::-moz-table-column-group',
'::-moz-table-outer',
'::-moz-table-row',
'::-moz-table-row-group',
':-moz-ui-invalid',
':-moz-ui-valid',
':-moz-user-disabled',
'::-moz-viewport',
'::-moz-viewport-scroll',
':-moz-window-inactive',
'-moz-device-pixel-ratio',
'-moz-os-version',
'-moz-touch-enabled',
'-moz-windows-glass',
'-moz-alt-content'
]);
function isLength(dimension) {
return 'unit' in dimension && dimensionUnits.has(dimension.unit.toLowerCase());
}
function isResolution(dimension) {
return 'unit' in dimension && ['dpi', 'dpcm', 'dppx', 'x'].includes(dimension.unit.toLowerCase());
}
function isAngle(dimension) {
return 'unit' in dimension && ['rad', 'turn', 'deg', 'grad'].includes(dimension.unit.toLowerCase());
}
function isTime(dimension) {
return 'unit' in dimension && ['ms', 's'].includes(dimension.unit.toLowerCase());
}
function isFrequency(dimension) {
return 'unit' in dimension && ['hz', 'khz'].includes(dimension.unit.toLowerCase());
}
function isColorspace(token) {
if (token.typ != EnumToken.IdenTokenType) {
return false;
}
return ['srgb', 'srgb-linear', 'lab', 'oklab', 'lch', 'oklch', 'xyz', 'xyz-d50', 'xyz-d65', 'display-p3', 'a98-rgb', 'prophoto-rgb', 'rec2020', 'rgb', 'hsl', 'hwb'].includes(token.val.toLowerCase());
}
function isRectangularOrthogonalColorspace(token) {
if (token.typ != EnumToken.IdenTokenType) {
return false;
}
return ['srgb', 'srgb-linear', 'display-p3', 'a98-rgb', 'prophoto-rgb', 'rec2020', 'lab', 'oklab', 'xyz', 'xyz-d50', 'xyz-d65'].includes(token.val.toLowerCase());
}
function isPolarColorspace(token) {
if (token.typ != EnumToken.IdenTokenType) {
return false;
}
return ['hsl', 'hwb', 'lch', 'oklch'].includes(token.val);
}
function isHueInterpolationMethod(token) {
if (token.typ != EnumToken.IdenTokenType) {
return false;
}
return ['shorter', 'longer', 'increasing', 'decreasing'].includes(token.val);
}
function isColor(token) {
if (token.typ == EnumToken.ColorTokenType) {
return true;
}
if (token.typ == EnumToken.IdenTokenType) {
// named color
return token.val.toLowerCase() in COLORS_NAMES;
}
let isLegacySyntax = false;
if (token.typ == EnumToken.FunctionTokenType && token.chi.length > 0 && colorsFunc.includes(token.val)) {
if (token.val == 'light-dark') {
const children = token.chi.filter((t) => [EnumToken.IdenTokenType, EnumToken.NumberTokenType, EnumToken.LiteralTokenType, EnumToken.ColorTokenType, EnumToken.FunctionTokenType, EnumToken.PercentageTokenType].includes(t.typ));
if (children.length != 2) {
return false;
}
if (isColor(children[0]) && isColor(children[1])) {
return true;
}
}
if (token.val == 'color') {
const children = token.chi.filter((t) => [EnumToken.IdenTokenType, EnumToken.NumberTokenType, EnumToken.LiteralTokenType, EnumToken.ColorTokenType, EnumToken.FunctionTokenType, EnumToken.PercentageTokenType].includes(t.typ));
const isRelative = children[0].typ == EnumToken.IdenTokenType && children[0].val == 'from';
if (children.length < 4 || children.length > 8) {
return false;
}
if (!isRelative && !isColorspace(children[0])) {
return false;
}
for (let i = 1; i < children.length - 2; i++) {
if (children[i].typ == EnumToken.IdenTokenType) {
if (children[i].val != 'none' &&
!(isRelative && ['alpha', 'r', 'g', 'b', 'x', 'y', 'z'].includes(children[i].val) || isColorspace(children[i]))) {
return false;
}
}
if (children[i].typ == EnumToken.FunctionTokenType && !mathFuncs.includes(children[i].val)) {
return false;
}
}
if (children.length == 4 || (isRelative && children.length == 6)) {
return true;
}
if (children.length == 8 || children.length == 6) {
const sep = children.at(-2);
const alpha = children.at(-1);
// @ts-ignore
if ((children.length > 6 || !isRelative) && sep.typ != EnumToken.LiteralTokenType || sep.val != '/') {
return false;
}
if (alpha.typ == EnumToken.IdenTokenType && alpha.val != 'none') {
return false;
}
else {
// @ts-ignore
if (alpha.typ == EnumToken.PercentageTokenType) {
if (+alpha.val < 0 || +alpha.val > 100) {
return false;
}
}
else if (alpha.typ == EnumToken.NumberTokenType) {
if (+alpha.val < 0 || +alpha.val > 1) {
return false;
}
}
}
}
return true;
}
else if (token.val == 'color-mix') {
const children = token.chi.reduce((acc, t) => {
if (t.typ == EnumToken.CommaTokenType) {
acc.push([]);
}
else {
if (![EnumToken.WhitespaceTokenType, EnumToken.CommentTokenType].includes(t.typ)) {
acc[acc.length - 1].push(t);
}
}
return acc;
}, [[]]);
if (children.length == 3) {
if (children[0].length > 3 ||
children[0][0].typ != EnumToken.IdenTokenType ||
children[0][0].val != 'in' ||
!isColorspace(children[0][1]) ||
(children[0].length == 3 && !isHueInterpolationMethod(children[0][2])) ||
children[1].length > 2 ||
children[1][0].typ != EnumToken.ColorTokenType ||
children[2].length > 2 ||
children[2][0].typ != EnumToken.ColorTokenType) {
return false;
}
if (children[1].length == 2) {
if (!(children[1][1].typ == EnumToken.PercentageTokenType || (children[1][1].typ == EnumToken.NumberTokenType && children[1][1].val == '0'))) {
return false;
}
}
if (children[2].length == 2) {
if (!(children[2][1].typ == EnumToken.PercentageTokenType || (children[2][1].typ == EnumToken.NumberTokenType && children[2][1].val == '0'))) {
return false;
}
}
return true;
}
return false;
}
else {
const keywords = ['from', 'none'];
if (['rgb', 'hsl', 'hwb', 'lab', 'lch', 'oklab', 'oklch'].includes(token.val)) {
keywords.push('alpha', ...token.val.slice(-3).split(''));
}
// @ts-ignore
for (const v of token.chi) {
if (v.typ == EnumToken.CommaTokenType) {
isLegacySyntax = true;
}
if (v.typ == EnumToken.IdenTokenType) {
if (!(keywords.includes(v.val) || v.val.toLowerCase() in COLORS_NAMES)) {
return false;
}
if (keywords.includes(v.val)) {
if (isLegacySyntax) {
return false;
}
if (v.val == 'from' && ['rgba', 'hsla'].includes(token.val)) {
return false;
}
}
continue;
}
if (v.typ == EnumToken.FunctionTokenType && (mathFuncs.includes(v.val) || v.val == 'var' || colorsFunc.includes(v.val))) {
continue;
}
if (![EnumToken.ColorTokenType, EnumToken.IdenTokenType, EnumToken.NumberTokenType, EnumToken.AngleTokenType, EnumToken.PercentageTokenType, EnumToken.CommaTokenType, EnumToken.WhitespaceTokenType, EnumToken.LiteralTokenType].includes(v.typ)) {
return false;
}
}
}
return true;
}
return false;
}
function isLetter(codepoint) {
// lowercase
return (codepoint >= 0x61 && codepoint <= 0x7a) ||
// uppercase
(codepoint >= 0x41 && codepoint <= 0x5a);
}
function isNonAscii(codepoint) {
return codepoint >= 0x80;
}
function isIdentStart(codepoint) {
// _
return codepoint == 0x5f || isLetter(codepoint) || isNonAscii(codepoint) || codepoint == REVERSE_SOLIDUS;
}
function isDigit(codepoint) {
return codepoint >= 0x30 && codepoint <= 0x39;
}
function isIdentCodepoint(codepoint) {
// -
return codepoint == 0x2d || isDigit(codepoint) || isIdentStart(codepoint);
}
function isIdent(name) {
const j = name.length - 1;
let i = 0;
let codepoint = name.charCodeAt(0);
// -
if (codepoint == 0x2d) {
const nextCodepoint = name.charCodeAt(1);
if (Number.isNaN(nextCodepoint)) {
return false;
}
// -
if (nextCodepoint == 0x2d) {
return true;
}
if (nextCodepoint == REVERSE_SOLIDUS) {
return name.length > 2 && !isNewLine(name.charCodeAt(2));
}
return true;
}
if (!isIdentStart(codepoint)) {
return false;
}
if (codepoint == REVERSE_SOLIDUS) {
codepoint = name.codePointAt(i + 1);
if (!isIdentCodepoint(codepoint)) {
return false;
}
i += String.fromCodePoint(codepoint).length;
if (i < j) {
codepoint = name.codePointAt(i);
if (!isIdentCodepoint(codepoint)) {
return false;
}
}
}
while (i < j) {
i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length;
codepoint = name.charCodeAt(i);
if (codepoint == REVERSE_SOLIDUS) {
i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length;
codepoint = name.charCodeAt(i);
i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length;
continue;
}
if (!isIdentCodepoint(codepoint)) {
return false;
}
}
return true;
}
function isNonPrintable(codepoint) {
// null -> backspace
return (codepoint >= 0 && codepoint <= 0x8) ||
// tab
codepoint == 0xb ||
// delete
codepoint == 0x7f ||
(codepoint >= 0xe && codepoint <= 0x1f);
}
function isPseudo(name) {
return name.charAt(0) == ':' &&
((name.endsWith('(') && isIdent(name.charAt(1) == ':' ? name.slice(2, -1) : name.slice(1, -1))) ||
isIdent(name.charAt(1) == ':' ? name.slice(2) : name.slice(1)));
}
function isHash(name) {
return name.charAt(0) == '#' && isIdent(name.charAt(1));
}
function isNumber(name) {
if (name.length == 0) {
return false;
}
let codepoint = name.charCodeAt(0);
let i = 0;
const j = name.length;
if (j == 1 && !isDigit(codepoint)) {
return false;
}
// '+' '-'
if ([0x2b, 0x2d].includes(codepoint)) {
i++;
}
// consume digits
while (i < j) {
codepoint = name.charCodeAt(i);
if (isDigit(codepoint)) {
i++;
continue;
}
// '.' 'E' 'e'
if (codepoint == 0x2e || codepoint == 0x45 || codepoint == 0x65) {
break;
}
return false;
}
// '.'
if (codepoint == 0x2e) {
if (!isDigit(name.charCodeAt(++i))) {
return false;
}
}
while (i < j) {
codepoint = name.charCodeAt(i);
if (isDigit(codepoint)) {
i++;
continue;
}
// 'E' 'e'
if (codepoint == 0x45 || codepoint == 0x65) {
i++;
break;
}
return false;
}
// 'E' 'e'
if (codepoint == 0x45 || codepoint == 0x65) {
if (i == j) {
return false;
}
codepoint = name.charCodeAt(i + 1);
// '+' '-'
if ([0x2b, 0x2d].includes(codepoint)) {
i++;
}
codepoint = name.charCodeAt(i + 1);
if (!isDigit(codepoint)) {
return false;
}
}
while (++i < j) {
codepoint = name.charCodeAt(i);
if (!isDigit(codepoint)) {
return false;
}
}
return true;
}
function isDimension(name) {
let index = name.length;
while (index--) {
if (isLetter(name.charCodeAt(index))) {
continue;
}
index++;
break;
}
const number = name.slice(0, index);
return number.length > 0 && isIdentStart(name.charCodeAt(index)) && isNumber(number);
}
function isPercentage(name) {
return name.endsWith('%') && isNumber(name.slice(0, -1));
}
function isFlex(name) {
return name.endsWith('fr') && isNumber(name.slice(0, -2));
}
function parseDimension(name) {
let index = name.length;
while (index--) {
if (isLetter(name.charCodeAt(index))) {
continue;
}
index++;
break;
}
const dimension = {
typ: EnumToken.DimensionTokenType,
val: name.slice(0, index),
unit: name.slice(index)
};
if (isAngle(dimension)) {
// @ts-ignore
dimension.typ = EnumToken.AngleTokenType;
}
else if (isLength(dimension)) {
// @ts-ignore
dimension.typ = EnumToken.LengthTokenType;
}
else if (isTime(dimension)) {
// @ts-ignore
dimension.typ = EnumToken.TimeTokenType;
}
else if (isResolution(dimension)) {
// @ts-ignore
dimension.typ = EnumToken.ResolutionTokenType;
if (dimension.unit == 'dppx') {
dimension.unit = 'x';
}
}
else if (isFrequency(dimension)) {
// @ts-ignore
dimension.typ = EnumToken.FrequencyTokenType;
}
return dimension;
}
function isHexColor(name) {
if (name.charAt(0) != '#' || ![4, 5, 7, 9].includes(name.length)) {
return false;
}
for (let chr of name.slice(1)) {
let codepoint = chr.charCodeAt(0);
if (!isDigit(codepoint) &&
// A-F
!(codepoint >= 0x41 && codepoint <= 0x46) &&
// a-f
!(codepoint >= 0x61 && codepoint <= 0x66)) {
return false;
}
}
return true;
}
/*
export function isHexDigit(name: string): boolean {
if (name.length || name.length > 6) {
return false;
}
for (let chr of name) {
let codepoint = <number>chr.charCodeAt(0);
if (!isDigit(codepoint) &&
// A F
!(codepoint >= 0x41 && codepoint <= 0x46) &&
// a f
!(codepoint >= 0x61 && codepoint <= 0x66)) {
return false;
}
}
return true;
}
*/
function isFunction(name) {
return name.endsWith('(') && isIdent(name.slice(0, -1));
}
function isAtKeyword(name) {
return name.charCodeAt(0) == 0x40 && isIdent(name.slice(1));
}
function isNewLine(codepoint) {
// \n \r \f
return codepoint == 0xa || codepoint == 0xc || codepoint == 0xd;
}
function isWhiteSpace(codepoint) {
return codepoint == 0x9 || codepoint == 0x20 ||
// isNewLine
codepoint == 0xa || codepoint == 0xc || codepoint == 0xd;
}
export { colorFontTech, fontFeaturesTech, fontFormat, isAngle, isAtKeyword, isColor, isColorspace, isDigit, isDimension, isFlex, isFrequency, isFunction, isHash, isHexColor, isHueInterpolationMethod, isIdent, isIdentCodepoint, isIdentStart, isLength, isNewLine, isNonPrintable, isNumber, isPercentage, isPolarColorspace, isPseudo, isRectangularOrthogonalColorspace, isResolution, isTime, isWhiteSpace, mathFuncs, mediaTypes, mozExtensions, parseDimension, pseudoElements, webkitExtensions, webkitPseudoAliasMap };