Skip to content
This repository has been archived by the owner on Feb 17, 2024. It is now read-only.

Commit

Permalink
init commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Bart Veneman committed Dec 7, 2023
1 parent 6fb97b9 commit a999866
Show file tree
Hide file tree
Showing 8 changed files with 6,666 additions and 0 deletions.
34 changes: 34 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
# For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages

name: NPM Publish

on:
release:
types: [created]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- run: npm install --ignore-scripts --no-audit
- run: npm test

publish-npm:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
registry-url: https://registry.npmjs.org/
- run: npm install --ignore-scripts --no-audit
- run: npm run build
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
24 changes: 24 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions

name: Tests

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
name: Unit tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Use Node.js 20
uses: actions/setup-node@v3
with:
node-version: 20
cache: "npm"
- run: npm install --ignore-scripts --no-audit
- run: npm test
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
dist
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# minify-css

Fast, small, zero-config library to minify CSS with basic rules. Simplicity, bundle size and runtime speed are more important than versatility and extensibility.

## Installation

```
npm install @projectwallace/minify-css
```

## Usage

```js
import { minify } from "@projectwallace/minify-css";

let old_css = "/* Your CSS here */";
let new_css = minify(old_css);
```

TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO Need more examples?

- [StackBlitz example using CommonJS](https://stackblitz.com/edit/stackblitz-starters-phchci?file=index.js)
- [StackBlitz example using ES Modules](https://stackblitz.com/edit/stackblitz-starters-hrhsed?file=index.js)

## Acknowledgements

- Thanks to [CSSTree](https://github.com/csstree/csstree) for providing the necessary parser and the interfaces for our CSS Types (the **bold** elements in the list above)

## Related projects

- [Minify CSS online](https://www.projectwallace.com/minify-css?utm_source=github&utm_medium=wallace_minify_css_related_projects) - See this minifier in action online!
- [CSS Analyzer](https://github.com/projectwallace/css-analyzer) - The best CSS analyzer that powers all analysis on [projectwallace.com](https://www.projectwallace.com?utm_source=github&utm_medium=wallace_minify_css_related_projects)
- [Format CSS](https://github.com/projectwallace/format-css) The exact opposite of this library: fast, small, zero-config CSS formatter.
151 changes: 151 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import { parse } from 'css-tree'

/**
* @param {import('css-tree').CssNode} node
* @param {string} css
*/
function substr(node, css) {
if (!node.loc) return ''
let str = css.substring(node.loc.start.offset, node.loc.end.offset)

// Single-line node, most common case
if (node.loc.start.line === node.loc.end.line) {
return str
}

// Multi-line nodes, not common
return str.replace(/\n/g, ' ')
}

/**
* @param {import('css-tree').Rule} node
* @param {string} css
*/
function print_rule(node, css) {
let buffer = ''

if (node.prelude !== null) {
if (node.prelude.type === 'SelectorList') {
buffer += print_selectorlist(node.prelude, css)
}
}

if (node.block !== null && node.block.type === 'Block') {
buffer += print_block(node.block, css)
}

return buffer
}

/**
* @param {import('css-tree').SelectorList} node
* @param {string} css
*/
function print_selectorlist(node, css) {
let buffer = ''

for (let selector of node.children) {
if (selector.type === 'Selector') {
buffer += substr(selector, css)
}

if (selector !== node.children.last) {
buffer += ','
}
}
return buffer
}

/**
* @param {import('css-tree').Block} node
* @param {string} css
*/
function print_block(node, css) {
let children = node.children

if (children.isEmpty) {
return '{}'
}

let buffer = '{'

for (let child of children) {
if (child.type === 'Declaration') {
buffer += print_declaration(child, css)
if (child !== children.last) {
buffer += ';'
}
} else if (child.type === 'Rule') {
buffer += print_rule(child, css)
} else if (child.type === 'Atrule') {
buffer += print_atrule(child, css)
}
}

buffer += '}'

return buffer
}

/**
* @param {import('css-tree').Atrule} node
* @param {string} css
*/
function print_atrule(node, css) {
let buffer = '@' + node.name + ' '

// @font-face has no prelude
if (node.prelude) {
buffer += substr(node.prelude, css).replace(/\s+/g, ' ')
}

if (node.block && node.block.type === 'Block') {
buffer += print_block(node.block, css)
} else {
// `@import url(style.css);` has no block, neither does `@layer layer1;`
buffer += ';'
}

return buffer
}

/**
* @param {import('css-tree').Declaration} node
* @param {string} css
*/
function print_declaration(node, css) {
return node.property + ':' + substr(node.value, css)
}

/**
* @param {import('css-tree').CssNode} node
* @param {string} css
*/
function print(node, css) {
let buffer = ''

if (node.children !== null) {
let children = node.children

for (let child of children) {
if (child.type === 'Rule') {
buffer += print_rule(child, css)
} else if (child.type === 'Atrule') {
buffer += print_atrule(child, css)
}
}
}

return buffer
}

/** @param {string} css */
export function minify(css) {
let ast = parse(css, {
positions: true,
parseAtrulePrelude: false,
parseCustomProperty: false,
parseValue: false
})
return print(ast, css)
}
Loading

0 comments on commit a999866

Please sign in to comment.