UNPKG

13.8 kBJavaScriptView Raw
1const MODES = (hljs) => {
2 return {
3 IMPORTANT: {
4 scope: 'meta',
5 begin: '!important'
6 },
7 BLOCK_COMMENT: hljs.C_BLOCK_COMMENT_MODE,
8 HEXCOLOR: {
9 scope: 'number',
10 begin: /#(([0-9a-fA-F]{3,4})|(([0-9a-fA-F]{2}){3,4}))\b/
11 },
12 FUNCTION_DISPATCH: {
13 className: "built_in",
14 begin: /[\w-]+(?=\()/
15 },
16 ATTRIBUTE_SELECTOR_MODE: {
17 scope: 'selector-attr',
18 begin: /\[/,
19 end: /\]/,
20 illegal: '$',
21 contains: [
22 hljs.APOS_STRING_MODE,
23 hljs.QUOTE_STRING_MODE
24 ]
25 },
26 CSS_NUMBER_MODE: {
27 scope: 'number',
28 begin: hljs.NUMBER_RE + '(' +
29 '%|em|ex|ch|rem' +
30 '|vw|vh|vmin|vmax' +
31 '|cm|mm|in|pt|pc|px' +
32 '|deg|grad|rad|turn' +
33 '|s|ms' +
34 '|Hz|kHz' +
35 '|dpi|dpcm|dppx' +
36 ')?',
37 relevance: 0
38 },
39 CSS_VARIABLE: {
40 className: "attr",
41 begin: /--[A-Za-z][A-Za-z0-9_-]*/
42 }
43 };
44};
45
46const TAGS = [
47 'a',
48 'abbr',
49 'address',
50 'article',
51 'aside',
52 'audio',
53 'b',
54 'blockquote',
55 'body',
56 'button',
57 'canvas',
58 'caption',
59 'cite',
60 'code',
61 'dd',
62 'del',
63 'details',
64 'dfn',
65 'div',
66 'dl',
67 'dt',
68 'em',
69 'fieldset',
70 'figcaption',
71 'figure',
72 'footer',
73 'form',
74 'h1',
75 'h2',
76 'h3',
77 'h4',
78 'h5',
79 'h6',
80 'header',
81 'hgroup',
82 'html',
83 'i',
84 'iframe',
85 'img',
86 'input',
87 'ins',
88 'kbd',
89 'label',
90 'legend',
91 'li',
92 'main',
93 'mark',
94 'menu',
95 'nav',
96 'object',
97 'ol',
98 'p',
99 'q',
100 'quote',
101 'samp',
102 'section',
103 'span',
104 'strong',
105 'summary',
106 'sup',
107 'table',
108 'tbody',
109 'td',
110 'textarea',
111 'tfoot',
112 'th',
113 'thead',
114 'time',
115 'tr',
116 'ul',
117 'var',
118 'video'
119];
120
121const MEDIA_FEATURES = [
122 'any-hover',
123 'any-pointer',
124 'aspect-ratio',
125 'color',
126 'color-gamut',
127 'color-index',
128 'device-aspect-ratio',
129 'device-height',
130 'device-width',
131 'display-mode',
132 'forced-colors',
133 'grid',
134 'height',
135 'hover',
136 'inverted-colors',
137 'monochrome',
138 'orientation',
139 'overflow-block',
140 'overflow-inline',
141 'pointer',
142 'prefers-color-scheme',
143 'prefers-contrast',
144 'prefers-reduced-motion',
145 'prefers-reduced-transparency',
146 'resolution',
147 'scan',
148 'scripting',
149 'update',
150 'width',
151 // TODO: find a better solution?
152 'min-width',
153 'max-width',
154 'min-height',
155 'max-height'
156];
157
158// https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes
159const PSEUDO_CLASSES = [
160 'active',
161 'any-link',
162 'blank',
163 'checked',
164 'current',
165 'default',
166 'defined',
167 'dir', // dir()
168 'disabled',
169 'drop',
170 'empty',
171 'enabled',
172 'first',
173 'first-child',
174 'first-of-type',
175 'fullscreen',
176 'future',
177 'focus',
178 'focus-visible',
179 'focus-within',
180 'has', // has()
181 'host', // host or host()
182 'host-context', // host-context()
183 'hover',
184 'indeterminate',
185 'in-range',
186 'invalid',
187 'is', // is()
188 'lang', // lang()
189 'last-child',
190 'last-of-type',
191 'left',
192 'link',
193 'local-link',
194 'not', // not()
195 'nth-child', // nth-child()
196 'nth-col', // nth-col()
197 'nth-last-child', // nth-last-child()
198 'nth-last-col', // nth-last-col()
199 'nth-last-of-type', //nth-last-of-type()
200 'nth-of-type', //nth-of-type()
201 'only-child',
202 'only-of-type',
203 'optional',
204 'out-of-range',
205 'past',
206 'placeholder-shown',
207 'read-only',
208 'read-write',
209 'required',
210 'right',
211 'root',
212 'scope',
213 'target',
214 'target-within',
215 'user-invalid',
216 'valid',
217 'visited',
218 'where' // where()
219];
220
221// https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements
222const PSEUDO_ELEMENTS = [
223 'after',
224 'backdrop',
225 'before',
226 'cue',
227 'cue-region',
228 'first-letter',
229 'first-line',
230 'grammar-error',
231 'marker',
232 'part',
233 'placeholder',
234 'selection',
235 'slotted',
236 'spelling-error'
237];
238
239const ATTRIBUTES = [
240 'align-content',
241 'align-items',
242 'align-self',
243 'all',
244 'animation',
245 'animation-delay',
246 'animation-direction',
247 'animation-duration',
248 'animation-fill-mode',
249 'animation-iteration-count',
250 'animation-name',
251 'animation-play-state',
252 'animation-timing-function',
253 'backface-visibility',
254 'background',
255 'background-attachment',
256 'background-clip',
257 'background-color',
258 'background-image',
259 'background-origin',
260 'background-position',
261 'background-repeat',
262 'background-size',
263 'border',
264 'border-bottom',
265 'border-bottom-color',
266 'border-bottom-left-radius',
267 'border-bottom-right-radius',
268 'border-bottom-style',
269 'border-bottom-width',
270 'border-collapse',
271 'border-color',
272 'border-image',
273 'border-image-outset',
274 'border-image-repeat',
275 'border-image-slice',
276 'border-image-source',
277 'border-image-width',
278 'border-left',
279 'border-left-color',
280 'border-left-style',
281 'border-left-width',
282 'border-radius',
283 'border-right',
284 'border-right-color',
285 'border-right-style',
286 'border-right-width',
287 'border-spacing',
288 'border-style',
289 'border-top',
290 'border-top-color',
291 'border-top-left-radius',
292 'border-top-right-radius',
293 'border-top-style',
294 'border-top-width',
295 'border-width',
296 'bottom',
297 'box-decoration-break',
298 'box-shadow',
299 'box-sizing',
300 'break-after',
301 'break-before',
302 'break-inside',
303 'caption-side',
304 'caret-color',
305 'clear',
306 'clip',
307 'clip-path',
308 'clip-rule',
309 'color',
310 'column-count',
311 'column-fill',
312 'column-gap',
313 'column-rule',
314 'column-rule-color',
315 'column-rule-style',
316 'column-rule-width',
317 'column-span',
318 'column-width',
319 'columns',
320 'contain',
321 'content',
322 'content-visibility',
323 'counter-increment',
324 'counter-reset',
325 'cue',
326 'cue-after',
327 'cue-before',
328 'cursor',
329 'direction',
330 'display',
331 'empty-cells',
332 'filter',
333 'flex',
334 'flex-basis',
335 'flex-direction',
336 'flex-flow',
337 'flex-grow',
338 'flex-shrink',
339 'flex-wrap',
340 'float',
341 'flow',
342 'font',
343 'font-display',
344 'font-family',
345 'font-feature-settings',
346 'font-kerning',
347 'font-language-override',
348 'font-size',
349 'font-size-adjust',
350 'font-smoothing',
351 'font-stretch',
352 'font-style',
353 'font-synthesis',
354 'font-variant',
355 'font-variant-caps',
356 'font-variant-east-asian',
357 'font-variant-ligatures',
358 'font-variant-numeric',
359 'font-variant-position',
360 'font-variation-settings',
361 'font-weight',
362 'gap',
363 'glyph-orientation-vertical',
364 'grid',
365 'grid-area',
366 'grid-auto-columns',
367 'grid-auto-flow',
368 'grid-auto-rows',
369 'grid-column',
370 'grid-column-end',
371 'grid-column-start',
372 'grid-gap',
373 'grid-row',
374 'grid-row-end',
375 'grid-row-start',
376 'grid-template',
377 'grid-template-areas',
378 'grid-template-columns',
379 'grid-template-rows',
380 'hanging-punctuation',
381 'height',
382 'hyphens',
383 'icon',
384 'image-orientation',
385 'image-rendering',
386 'image-resolution',
387 'ime-mode',
388 'isolation',
389 'justify-content',
390 'left',
391 'letter-spacing',
392 'line-break',
393 'line-height',
394 'list-style',
395 'list-style-image',
396 'list-style-position',
397 'list-style-type',
398 'margin',
399 'margin-bottom',
400 'margin-left',
401 'margin-right',
402 'margin-top',
403 'marks',
404 'mask',
405 'mask-border',
406 'mask-border-mode',
407 'mask-border-outset',
408 'mask-border-repeat',
409 'mask-border-slice',
410 'mask-border-source',
411 'mask-border-width',
412 'mask-clip',
413 'mask-composite',
414 'mask-image',
415 'mask-mode',
416 'mask-origin',
417 'mask-position',
418 'mask-repeat',
419 'mask-size',
420 'mask-type',
421 'max-height',
422 'max-width',
423 'min-height',
424 'min-width',
425 'mix-blend-mode',
426 'nav-down',
427 'nav-index',
428 'nav-left',
429 'nav-right',
430 'nav-up',
431 'none',
432 'normal',
433 'object-fit',
434 'object-position',
435 'opacity',
436 'order',
437 'orphans',
438 'outline',
439 'outline-color',
440 'outline-offset',
441 'outline-style',
442 'outline-width',
443 'overflow',
444 'overflow-wrap',
445 'overflow-x',
446 'overflow-y',
447 'padding',
448 'padding-bottom',
449 'padding-left',
450 'padding-right',
451 'padding-top',
452 'page-break-after',
453 'page-break-before',
454 'page-break-inside',
455 'pause',
456 'pause-after',
457 'pause-before',
458 'perspective',
459 'perspective-origin',
460 'pointer-events',
461 'position',
462 'quotes',
463 'resize',
464 'rest',
465 'rest-after',
466 'rest-before',
467 'right',
468 'row-gap',
469 'scroll-margin',
470 'scroll-margin-block',
471 'scroll-margin-block-end',
472 'scroll-margin-block-start',
473 'scroll-margin-bottom',
474 'scroll-margin-inline',
475 'scroll-margin-inline-end',
476 'scroll-margin-inline-start',
477 'scroll-margin-left',
478 'scroll-margin-right',
479 'scroll-margin-top',
480 'scroll-padding',
481 'scroll-padding-block',
482 'scroll-padding-block-end',
483 'scroll-padding-block-start',
484 'scroll-padding-bottom',
485 'scroll-padding-inline',
486 'scroll-padding-inline-end',
487 'scroll-padding-inline-start',
488 'scroll-padding-left',
489 'scroll-padding-right',
490 'scroll-padding-top',
491 'scroll-snap-align',
492 'scroll-snap-stop',
493 'scroll-snap-type',
494 'shape-image-threshold',
495 'shape-margin',
496 'shape-outside',
497 'speak',
498 'speak-as',
499 'src', // @font-face
500 'tab-size',
501 'table-layout',
502 'text-align',
503 'text-align-all',
504 'text-align-last',
505 'text-combine-upright',
506 'text-decoration',
507 'text-decoration-color',
508 'text-decoration-line',
509 'text-decoration-style',
510 'text-emphasis',
511 'text-emphasis-color',
512 'text-emphasis-position',
513 'text-emphasis-style',
514 'text-indent',
515 'text-justify',
516 'text-orientation',
517 'text-overflow',
518 'text-rendering',
519 'text-shadow',
520 'text-transform',
521 'text-underline-position',
522 'top',
523 'transform',
524 'transform-box',
525 'transform-origin',
526 'transform-style',
527 'transition',
528 'transition-delay',
529 'transition-duration',
530 'transition-property',
531 'transition-timing-function',
532 'unicode-bidi',
533 'vertical-align',
534 'visibility',
535 'voice-balance',
536 'voice-duration',
537 'voice-family',
538 'voice-pitch',
539 'voice-range',
540 'voice-rate',
541 'voice-stress',
542 'voice-volume',
543 'white-space',
544 'widows',
545 'width',
546 'will-change',
547 'word-break',
548 'word-spacing',
549 'word-wrap',
550 'writing-mode',
551 'z-index'
552 // reverse makes sure longer attributes `font-weight` are matched fully
553 // instead of getting false positives on say `font`
554].reverse();
555
556/*
557Language: CSS
558Category: common, css, web
559Website: https://developer.mozilla.org/en-US/docs/Web/CSS
560*/
561
562/** @type LanguageFn */
563function css(hljs) {
564 const regex = hljs.regex;
565 const modes = MODES(hljs);
566 const VENDOR_PREFIX = {
567 begin: /-(webkit|moz|ms|o)-(?=[a-z])/
568 };
569 const AT_MODIFIERS = "and or not only";
570 const AT_PROPERTY_RE = /@-?\w[\w]*(-\w+)*/; // @-webkit-keyframes
571 const IDENT_RE = '[a-zA-Z-][a-zA-Z0-9_-]*';
572 const STRINGS = [
573 hljs.APOS_STRING_MODE,
574 hljs.QUOTE_STRING_MODE
575 ];
576
577 return {
578 name: 'CSS',
579 case_insensitive: true,
580 illegal: /[=|'\$]/,
581 keywords: {
582 keyframePosition: "from to"
583 },
584 classNameAliases: {
585 // for visual continuity with `tag {}` and because we
586 // don't have a great class for this?
587 keyframePosition: "selector-tag"
588 },
589 contains: [
590 modes.BLOCK_COMMENT,
591 VENDOR_PREFIX,
592 // to recognize keyframe 40% etc which are outside the scope of our
593 // attribute value mode
594 modes.CSS_NUMBER_MODE,
595 {
596 className: 'selector-id',
597 begin: /#[A-Za-z0-9_-]+/,
598 relevance: 0
599 },
600 {
601 className: 'selector-class',
602 begin: '\\.' + IDENT_RE,
603 relevance: 0
604 },
605 modes.ATTRIBUTE_SELECTOR_MODE,
606 {
607 className: 'selector-pseudo',
608 variants: [
609 {
610 begin: ':(' + PSEUDO_CLASSES.join('|') + ')'
611 },
612 {
613 begin: ':(:)?(' + PSEUDO_ELEMENTS.join('|') + ')'
614 }
615 ]
616 },
617 // we may actually need this (12/2020)
618 // { // pseudo-selector params
619 // begin: /\(/,
620 // end: /\)/,
621 // contains: [ hljs.CSS_NUMBER_MODE ]
622 // },
623 modes.CSS_VARIABLE,
624 {
625 className: 'attribute',
626 begin: '\\b(' + ATTRIBUTES.join('|') + ')\\b'
627 },
628 // attribute values
629 {
630 begin: /:/,
631 end: /[;}{]/,
632 contains: [
633 modes.BLOCK_COMMENT,
634 modes.HEXCOLOR,
635 modes.IMPORTANT,
636 modes.CSS_NUMBER_MODE,
637 ...STRINGS,
638 // needed to highlight these as strings and to avoid issues with
639 // illegal characters that might be inside urls that would tigger the
640 // languages illegal stack
641 {
642 begin: /(url|data-uri)\(/,
643 end: /\)/,
644 relevance: 0, // from keywords
645 keywords: {
646 built_in: "url data-uri"
647 },
648 contains: [
649 {
650 className: "string",
651 // any character other than `)` as in `url()` will be the start
652 // of a string, which ends with `)` (from the parent mode)
653 begin: /[^)]/,
654 endsWithParent: true,
655 excludeEnd: true
656 }
657 ]
658 },
659 modes.FUNCTION_DISPATCH
660 ]
661 },
662 {
663 begin: regex.lookahead(/@/),
664 end: '[{;]',
665 relevance: 0,
666 illegal: /:/, // break on Less variables @var: ...
667 contains: [
668 {
669 className: 'keyword',
670 begin: AT_PROPERTY_RE
671 },
672 {
673 begin: /\s/,
674 endsWithParent: true,
675 excludeEnd: true,
676 relevance: 0,
677 keywords: {
678 $pattern: /[a-z-]+/,
679 keyword: AT_MODIFIERS,
680 attribute: MEDIA_FEATURES.join(" ")
681 },
682 contains: [
683 {
684 begin: /[a-z-]+(?=:)/,
685 className: "attribute"
686 },
687 ...STRINGS,
688 modes.CSS_NUMBER_MODE
689 ]
690 }
691 ]
692 },
693 {
694 className: 'selector-tag',
695 begin: '\\b(' + TAGS.join('|') + ')\\b'
696 }
697 ]
698 };
699}
700
701export { css as default };