You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP
Socket
Book a DemoInstallSign in
Socket

@tbela99/css-parser

Package Overview
Dependencies
Maintainers
1
Versions
31
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@tbela99/css-parser

CSS parser for node and the browser

0.2.0
Source
npmnpm
Version published
Weekly downloads
173
55.86%
Maintainers
1
Weekly downloads
 
Created
Source

npm cov

css-parser

CSS parser and minifier for node and the browser

Installation

$ npm install @tbela99/css-parser

Features

  • fault-tolerant parser, will try to fix invalid tokens according to the CSS syntax module 3 recommendations.
  • efficient minification, see benchmark
  • automatically generate nested css rules
  • generate sourcemap
  • compute css shorthands. see the list below
  • compute calc() expression
  • nested css expansion
  • remove duplicate properties
  • flatten @import rules
  • works the same way in node and web browser

Transform

Parse and render css in a single pass.

Usage


transform(css, transformOptions: TransformOptions = {}): TransformResult

Example


import {transform} from '@tbela99/css-parser';

const {ast, code, map, errors, stats} = await transform(css, {minify: true, resolveImport: true, cwd: 'files/css'});

TransformOptions

Include ParseOptions and RenderOptions

ParseOptions

  • minify: boolean, optional. default to true. optimize ast.
  • src: string, optional. original css file location to be used with sourcemap.
  • sourcemap: boolean, optional. preserve node location data.
  • nestingRules: boolean, optional. automatically generated nested rules.
  • expandNestingRules: boolean, optional. convert nesting rules into separate rules. will automatically set nestingRules to false.
  • removeCharset: boolean, optional. remove @charset.
  • removeEmpty: boolean, optional. remove empty rule lists from the ast.
  • resolveUrls: boolean, optional. resolve css 'url()' according to the parameters 'src' and 'cwd'
  • resolveImport: boolean, optional. replace @import rule by the content of its referenced stylesheet.
  • cwd: string, optional. the current working directory. when specified url() are resolved using this value
  • removeDuplicateDeclarations: boolean, optional. remove duplicate declarations.
  • computeShorthand: boolean, optional. compute shorthand properties.
  • inlineCssVariables: boolean, optional. replace css variables with their current value.
  • computeCalcExpression: boolean, optional. evaluate calc() expression
  • inlineCssVariables: boolean, optional. replace some css variables with their actual value. they must be declared once in the :root {} rule.
  • visitor: VisitorNodeMap, optional. node visitor used to transform the ast.
  • signal: AbortSignal, optional. abort parsing.

RenderOptions

  • minify: boolean, optional. default to true. minify css output.
  • expandNestingRules: boolean, optional. expand nesting rules.
  • sourcemap: boolean, optional. generate sourcemap
  • preserveLicense: boolean, force preserving comments starting with '/*!' when minify is enabled.
  • sourcemap: boolean, optional. generate sourcemap.
  • indent: string, optional. css indention string. uses space character by default.
  • newLine: string, optional. new line character.
  • removeComments: boolean, remove comments in generated css.
  • colorConvert: boolean, convert colors to hex.
  • output: string, optional. file where to store css. url() are resolved according to the specified value. no file is created though.
  • cwd: string, optional. value used as current working directory. when output is not provided, urls are resolved according to this value.

Parsing

Usage


parse(css, parseOptions = {})

Example


const {ast, errors, stats} = await parse(css);

Rendering

Usage

render(ast, RenderOptions = {});

Example

import {render} from '@tbela99/css-parser';

// minified
const {code, stats} = render(ast, {minify: true});

console.log(code);

Node Walker

import {walk} from '@tbela99/css-parser';

for (const {node, parent, root} of walk(ast)) {
    
    // do somehting
}

Exports

There are several ways to import the library into your application.

Node exports

import as a module


import {transform} from '@tbela99/css-parser';

// ...

import as a CommonJS module


const {transform} = require('@tbela99/css-parser/cjs');

// ...

Web export

Programmatic import


import {transform} from '@tbela99/css-parser/web';

// ...

Javascript module


<script src="dist/web/index.js" type="module"></script>

Single JavaScript file


<script src="dist/index-umd-web.js"></script>

Example 1

Automatic CSS Nesting

CSS

const {parse, render} = require("@tbela99/css-parser/cjs");

const css = `
table.colortable td {
 text-align:center;
}
table.colortable td.c {
 text-transform:uppercase;
}
table.colortable td:first-child, table.colortable td:first-child+td {
 border:1px solid black;
}
table.colortable th {
 text-align:center;
 background:black;
 color:white;
}
`;

const result = await parse(css, {nestingRules:true}).then(result => render(result.ast, {minify:false}).code);

Result

table.colortable {
 & td {
  text-align: center;
  &.c {
   text-transform: uppercase
  }
  &:first-child,&:first-child+td {
   border: 1px solid #000
  }
 }
 & th {
  text-align: center;
  background: #000;
  color: #fff
 }
}

Example 2

Nested CSS Expansion

CSS

table.colortable {
 & td {
  text-align: center;
  &.c {
   text-transform: uppercase
  }
  &:first-child,&:first-child+td {
   border: 1px solid #000
  }
 }
 & th {
  text-align: center;
  background: #000;
  color: #fff
 }
}

Javascript

import {parse, render} from '@tbela99/css-parser';


const options = {minify: true};

const {code} = await parse(css, options).then(result => render(result.ast, {minify: false, expandNestingRules: true}));
//
console.debug(code);

Result


table.colortable td {
  text-align:center;
}
table.colortable td.c {
  text-transform:uppercase;
}
table.colortable td:first-child, table.colortable td:first-child+td {
  border:1px solid black;
}
table.colortable th {
  text-align:center;
  background:black;
  color:white;
}

Example 3

Calc() resolution


import {parse, render} from '@tbela99/css-parser';

const css = `

.foo-bar {
    width: calc(100px * 2);
    height: calc(((75.37% - 63.5px) - 900px) + (2 * 100px));
    max-width: calc(3.5rem + calc(var(--bs-border-width) * 2));
}
`;

const prettyPrint = await parse(css).then(result => render(result.ast, {minify: false}).code);

result

.foo-bar {
    width: 200px;
    height: calc(75.37% - 763.5px);
    max-width: calc(3.5rem + var(--bs-border-width)*2)
}

Example 4

CSS variable inlining


import {parse, render} from '@tbela99/css-parser';

const css = `

:root {

--preferred-width: 20px;
}
.foo-bar {

    width: calc(calc(var(--preferred-width) + 1px) / 3 + 5px);
    height: calc(100% / 4);}
`

const prettyPrint = await parse(css, {inlineCssVariables: true}).then(result => render(result.ast, {minify: false}).code);

result

.foo-bar {
    width: 12px;
    height: 25%
}

AST

Comment

  • typ: string 'Comment'
  • val: string, the comment

Declaration

  • typ: string 'Declaration'
  • nam: string, declaration name
  • val: array of tokens

Rule

  • typ: string 'Rule'
  • sel: string, css selector
  • chi: array of children

AtRule

  • typ: string 'AtRule'
  • nam: string. AtRule name
  • val: rule prelude

AtRuleStyleSheet

  • typ: string 'Stylesheet'
  • chi: array of children

Sourcemap

  • sourcemap generation

Minification

  • reduce calc()
  • inline css variables
  • merge identical rules
  • merge adjacent rules
  • minify colors
  • minify numbers and Dimensions tokens
  • compute shorthand: see the list below
  • remove redundant declarations
  • conditionally unwrap :is()
  • automatic css nesting
  • automatically wrap selectors using :is()
  • avoid reparsing (declarations, selectors, at-rule)
  • node and browser versions
  • decode and replace utf-8 escape sequence

Computed shorthands properties

  • animation
  • background
  • border
  • border-bottom
  • border-color
  • border-left
  • border-radius
  • border-right
  • border-style
  • border-top
  • border-width
  • font
  • inset
  • list-style
  • margin
  • outline
  • overflow
  • padding
  • text-decoration
  • text-emphasis
  • transition

Performance

  • flatten @import

Node Transformation

Ast can be transformed using node visitors

Exemple 1: Declaration


import {AstDeclaration, ParserOptions} from "../src/@types";

const options: ParserOptions = {

    visitor: {

        Declaration: (node: AstDeclaration) => {

            if (node.nam == '-webkit-transform') {

                node.nam = 'transform'
            }
        }
    }
}

const css = `

.foo {
    -webkit-transform: scale(calc(100 * 2/ 15));
}
`;

console.debug(await transform(css, options));

// .foo{transform:scale(calc(40/3))}

Exemple 2: Declaration


import {AstDeclaration, LengthToken, ParserOptions} from "../src/@types";
import {EnumToken, NodeType} from "../src/lib";
import {transform} from "../src/node";

const options: ParserOptions = {

    visitor: {

        Declaration: {

            // called only for height declaration
            height: (node: AstDeclaration): AstDeclaration[] => {


                return [
                    node,
                    {

                        typ: NodeType.DeclarationNodeType,
                        nam: 'width',
                        val: [
                            <LengthToken>{
                                typ: EnumToken.Length,
                                val: '3',
                                unit: 'px'
                            }
                        ]
                    }
                ];
            }
        }
    }
};

const css = `

.foo {
    height: calc(100px * 2/ 15);
}
`;

console.debug(await transform(css, options));

// .foo{height:calc(40px/3);width:3px}

Exemple 3: At-Rule


import {AstAtRule, ParserOptions} from "../src/@types";
import {transform} from "../src/node";


const options: ParserOptions = {

    visitor: {

        AtRule: (node: AstAtRule): AstAtRule => {
            
            if (node.nam == 'media') {

                return {...node, val: 'all'}
            }
        }
    }
};

const css = `

@media screen {
       
    .foo {

            height: calc(100px * 2/ 15);    
    } 
}
`;

console.debug(await transform(css, options));

// .foo{height:calc(40px/3)}

Exemple 4: At-Rule


import {AstAtRule, ParserOptions} from "../src/@types";
import {transform} from "../src/node";

const options: ParserOptions = {

    visitor: {

        AtRule: {

            media: (node: AstAtRule): AstAtRule => {

                return {...node, val: 'all'}
            }
        }
    }
};

const css = `

@media screen {
       
    .foo {

            height: calc(100px * 2/ 15);    
    } 
}
`;

console.debug(await transform(css, options));

// .foo{height:calc(40px/3)}

Exemple 5: Rule


import {AstAtRule, ParserOptions} from "../src/@types";
import {transform} from "../src/node";

const options: ParserOptions = {

    visitor: {


        Rule (node: AstRule): AstRule {

            return {...node, sel: '.foo,.bar,.fubar'};
        }
    }
};

const css = `

    .foo {

            height: calc(100px * 2/ 15);    
    } 
`;

console.debug(await transform(css, options));

// .foo,.bar,.fubar{height:calc(40px/3)}

Thanks to Jetbrains for sponsoring this project with a free license

Keywords

parser

FAQs

Package last updated on 05 Jan 2024

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts