Skip to content

Commit

Permalink
chore(css-like) lint css grammars
Browse files Browse the repository at this point in the history
  • Loading branch information
joshgoebel committed Jan 29, 2021
1 parent 11a1a4b commit 960838e
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 64 deletions.
2 changes: 1 addition & 1 deletion src/languages/css.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export default function(hljs) {
// },
{
className: 'attribute',
begin: '\\b(' + css.ATTRIBUTES.reverse().join('|') + ')\\b',
begin: '\\b(' + css.ATTRIBUTES.reverse().join('|') + ')\\b'
},
// attribute values
{
Expand Down
127 changes: 85 additions & 42 deletions src/languages/less.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,37 @@ export default function(hljs) {
const modes = css.MODES(hljs);
const PSEUDO_SELECTORS = css.PSEUDO_SELECTORS;

var AT_MODIFIERS = "and or not only";
var IDENT_RE = '[\\w-]+'; // yes, Less identifiers may begin with a digit
var INTERP_IDENT_RE = '(' + IDENT_RE + '|@\\{' + IDENT_RE + '\\})';
const AT_MODIFIERS = "and or not only";
const IDENT_RE = '[\\w-]+'; // yes, Less identifiers may begin with a digit
const INTERP_IDENT_RE = '(' + IDENT_RE + '|@\\{' + IDENT_RE + '\\})';

/* Generic Modes */

var RULES = [], VALUE_MODES = []; // forward def. for recursive modes
const RULES = []; const VALUE_MODES = []; // forward def. for recursive modes

var STRING_MODE = function(c) { return {
const STRING_MODE = function(c) {
return {
// Less strings are not multiline (also include '~' for more consistent coloring of "escaped" strings)
className: 'string', begin: '~?' + c + '.*?' + c
};};
className: 'string',
begin: '~?' + c + '.*?' + c
};
};

var IDENT_MODE = function(name, begin, relevance) { return {
className: name, begin: begin, relevance: relevance
};};
const IDENT_MODE = function(name, begin, relevance) {
return {
className: name,
begin: begin,
relevance: relevance
};
};

var AT_KEYWORDS = {
const AT_KEYWORDS = {
$pattern: /[a-z-]+/,
keyword: AT_MODIFIERS,
attribute: css.MEDIA_FEATURES.join(" ")
};

var PARENS_MODE = {
const PARENS_MODE = {
// used only to properly balance nested parens inside mixin call, def. arg list
begin: '\\(',
end: '\\)',
Expand All @@ -54,26 +61,41 @@ export default function(hljs) {
hljs.CSS_NUMBER_MODE, // fixme: it does not include dot for numbers like .5em :(
{
begin: '(url|data-uri)\\(',
starts: {className: 'string', end: '[\\)\\n]', excludeEnd: true}
starts: {
className: 'string',
end: '[\\)\\n]',
excludeEnd: true
}
},
modes.HEXCOLOR,
PARENS_MODE,
IDENT_MODE('variable', '@@?' + IDENT_RE, 10),
IDENT_MODE('variable', '@\\{' + IDENT_RE + '\\}'),
IDENT_MODE('variable', '@\\{' + IDENT_RE + '\\}'),
IDENT_MODE('built_in', '~?`[^`]*?`'), // inline javascript (or whatever host language) *multiline* string
{ // @media features (it’s here to not duplicate things in AT_RULE_MODE with extra PARENS_MODE overriding):
className: 'attribute', begin: IDENT_RE + '\\s*:', end: ':', returnBegin: true, excludeEnd: true
className: 'attribute',
begin: IDENT_RE + '\\s*:',
end: ':',
returnBegin: true,
excludeEnd: true
},
modes.IMPORTANT
);

var VALUE_WITH_RULESETS = VALUE_MODES.concat({
begin: /\{/, end: /\}/, contains: RULES
const VALUE_WITH_RULESETS = VALUE_MODES.concat({
begin: /\{/,
end: /\}/,
contains: RULES
});

var MIXIN_GUARD_MODE = {
beginKeywords: 'when', endsWithParent: true,
contains: [{beginKeywords: 'and not'}].concat(VALUE_MODES) // using this form to override VALUE’s 'function' match
const MIXIN_GUARD_MODE = {
beginKeywords: 'when',
endsWithParent: true,
contains: [
{
beginKeywords: 'and not'
}
].concat(VALUE_MODES) // using this form to override VALUE’s 'function' match
};

/* Rule-Level Modes */
Expand All @@ -84,13 +106,16 @@ export default function(hljs) {
end: /[;}]/,
relevance: 0,
contains: [
{ begin: /-(webkit|moz|ms|o)-/ },
{
begin: /-(webkit|moz|ms|o)-/
},
{
className: 'attribute',
begin: '\\b(' + css.ATTRIBUTES.reverse().join('|') + ')\\b',
end: /(?=:)/,
starts: {
endsWithParent: true, illegal: '[<=$]',
endsWithParent: true,
illegal: '[<=$]',
relevance: 0,
contains: VALUE_MODES
}
Expand All @@ -111,46 +136,60 @@ export default function(hljs) {
};

// variable definitions and calls
var VAR_RULE_MODE = {
const VAR_RULE_MODE = {
className: 'variable',
variants: [
// using more strict pattern for higher relevance to increase chances of Less detection.
// this is *the only* Less specific statement used in most of the sources, so...
// (we’ll still often loose to the css-parser unless there's '//' comment,
// simply because 1 variable just can't beat 99 properties :)
{begin: '@' + IDENT_RE + '\\s*:', relevance: 15},
{begin: '@' + IDENT_RE}
{
begin: '@' + IDENT_RE + '\\s*:',
relevance: 15
},
{
begin: '@' + IDENT_RE
}
],
starts: {end: '[;}]', returnEnd: true, contains: VALUE_WITH_RULESETS}
starts: {
end: '[;}]',
returnEnd: true,
contains: VALUE_WITH_RULESETS
}
};

var SELECTOR_MODE = {
const SELECTOR_MODE = {
// first parse unambiguous selectors (i.e. those not starting with tag)
// then fall into the scary lookahead-discriminator variant.
// this mode also handles mixin definitions and calls
variants: [{
begin: '[\\.#:&\\[>]', end: '[;{}]' // mixin calls end with ';'
}, {
begin: INTERP_IDENT_RE, end: /\{/
}],
variants: [
{
begin: '[\\.#:&\\[>]',
end: '[;{}]' // mixin calls end with ';'
},
{
begin: INTERP_IDENT_RE,
end: /\{/
}
],
returnBegin: true,
returnEnd: true,
returnEnd: true,
illegal: '[<=\'$"]',
relevance: 0,
contains: [
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
MIXIN_GUARD_MODE,
IDENT_MODE('keyword', 'all\\b'),
IDENT_MODE('variable', '@\\{' + IDENT_RE + '\\}'), // otherwise it’s identified as tag
IDENT_MODE('keyword', 'all\\b'),
IDENT_MODE('variable', '@\\{' + IDENT_RE + '\\}'), // otherwise it’s identified as tag
{
begin: '\\b(' + css.TAGS.join('|') + ')\\b',
className: 'selector-tag'
},
IDENT_MODE('selector-tag', INTERP_IDENT_RE + '%?', 0), // '%' for more consistent coloring of @keyframes "tags"
IDENT_MODE('selector-tag', INTERP_IDENT_RE + '%?', 0), // '%' for more consistent coloring of @keyframes "tags"
IDENT_MODE('selector-id', '#' + INTERP_IDENT_RE),
IDENT_MODE('selector-class', '\\.' + INTERP_IDENT_RE, 0),
IDENT_MODE('selector-tag', '&', 0),
IDENT_MODE('selector-tag', '&', 0),
modes.ATTRIBUTE_SELECTOR_MODE,
{
className: 'selector-pseudo',
Expand All @@ -160,17 +199,21 @@ export default function(hljs) {
className: 'selector-pseudo',
begin: '::(' + css.PSEUDO_ELEMENTS.join('|') + ')'
},
{begin: '\\(', end: '\\)', contains: VALUE_WITH_RULESETS}, // argument list of parametric mixins
{begin: '!important'} // eat !important after mixin call or it will be colored as tag
{
begin: '\\(',
end: '\\)',
contains: VALUE_WITH_RULESETS
}, // argument list of parametric mixins
{
begin: '!important'
} // eat !important after mixin call or it will be colored as tag
]
};

const PSEUDO_SELECTOR_MODE = {
begin: IDENT_RE + ':(:)?' + `(${PSEUDO_SELECTORS.join('|')})`,
returnBegin: true,
contains: [
SELECTOR_MODE
]
contains: [ SELECTOR_MODE ]
};

RULES.push(
Expand Down
24 changes: 14 additions & 10 deletions src/languages/scss.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ export default function(hljs) {
const PSEUDO_ELEMENTS = css.PSEUDO_ELEMENTS;
const PSEUDO_CLASSES = css.PSEUDO_CLASSES;

var AT_IDENTIFIER = '@[a-z-]+' // @font-face
var AT_MODIFIERS = "and or not only"
var IDENT_RE = '[a-zA-Z-][a-zA-Z0-9_-]*';
var VARIABLE = {
const AT_IDENTIFIER = '@[a-z-]+'; // @font-face
const AT_MODIFIERS = "and or not only";
const IDENT_RE = '[a-zA-Z-][a-zA-Z0-9_-]*';
const VARIABLE = {
className: 'variable',
begin: '(\\$' + IDENT_RE + ')\\b'
};
Expand All @@ -30,11 +30,13 @@ export default function(hljs) {
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
{
className: 'selector-id', begin: '#[A-Za-z0-9_-]+',
className: 'selector-id',
begin: '#[A-Za-z0-9_-]+',
relevance: 0
},
{
className: 'selector-class', begin: '\\.[A-Za-z0-9_-]+',
className: 'selector-class',
begin: '\\.[A-Za-z0-9_-]+',
relevance: 0
},
modes.ATTRIBUTE_SELECTOR_MODE,
Expand All @@ -60,13 +62,14 @@ export default function(hljs) {
},
{
className: 'attribute',
begin: '\\b(' + css.ATTRIBUTES.reverse().join('|') + ')\\b',
begin: '\\b(' + css.ATTRIBUTES.reverse().join('|') + ')\\b'
},
{
begin: '\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b'
},
{
begin: ':', end: ';',
begin: ':',
end: ';',
contains: [
VARIABLE,
modes.HEXCOLOR,
Expand All @@ -85,7 +88,8 @@ export default function(hljs) {
keywords: '@page @font-face'
},
{
begin: '@', end: '[{;]',
begin: '@',
end: '[{;]',
returnBegin: true,
keywords: {
$pattern: /[a-z-]+/,
Expand All @@ -105,7 +109,7 @@ export default function(hljs) {
hljs.QUOTE_STRING_MODE,
hljs.APOS_STRING_MODE,
modes.HEXCOLOR,
hljs.CSS_NUMBER_MODE,
hljs.CSS_NUMBER_MODE
]
}
]
Expand Down
23 changes: 12 additions & 11 deletions src/languages/stylus.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ import * as css from "./lib/css-shared.js";
export default function(hljs) {
const modes = css.MODES(hljs);

var AT_MODIFIERS = "and or not only";
var VARIABLE = {
const AT_MODIFIERS = "and or not only";
const VARIABLE = {
className: 'variable',
begin: '\\$' + hljs.IDENT_RE
};

var AT_KEYWORDS = [
const AT_KEYWORDS = [
'charset',
'css',
'debug',
Expand All @@ -35,10 +35,10 @@ export default function(hljs) {
'while'
];

var LOOKAHEAD_TAG_END = '(?=[.\\s\\n[:,(])';
const LOOKAHEAD_TAG_END = '(?=[.\\s\\n[:,(])';

// illegals
var ILLEGAL = [
const ILLEGAL = [
'\\?',
'(\\bReturn\\b)', // monkey
'(\\bEnd\\b)', // monkey
Expand All @@ -49,12 +49,12 @@ export default function(hljs) {
'\\*\\s', // markdown
'===\\s', // markdown
'\\|',
'%', // prolog
'%' // prolog
];

return {
name: 'Stylus',
aliases: ['styl'],
aliases: [ 'styl' ],
case_insensitive: false,
keywords: 'if else for in',
illegal: '(' + ILLEGAL.join('|') + ')',
Expand Down Expand Up @@ -111,9 +111,7 @@ export default function(hljs) {
keyword: AT_MODIFIERS,
attribute: css.MEDIA_FEATURES.join(" ")
},
contains: [
hljs.CSS_NUMBER_MODE
]
contains: [ hljs.CSS_NUMBER_MODE ]
}
},

Expand All @@ -140,7 +138,10 @@ export default function(hljs) {
illegal: '[\\n]',
returnBegin: true,
contains: [
{className: 'title', begin: '\\b[a-zA-Z][a-zA-Z0-9_\-]*'},
{
className: 'title',
begin: '\\b[a-zA-Z][a-zA-Z0-9_\-]*'
},
{
className: 'params',
begin: /\(/,
Expand Down

0 comments on commit 960838e

Please sign in to comment.