Skip to content

Commit

Permalink
initial version
Browse files Browse the repository at this point in the history
  • Loading branch information
rofrischmann committed Nov 26, 2017
0 parents commit 5f56eaf
Show file tree
Hide file tree
Showing 28 changed files with 4,311 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"presets": [
"es2015",
"flow"
]
}
5 changes: 5 additions & 0 deletions .codeclimate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
languages:
Ruby: true
JavaScript: true
PHP: true
Python: true
37 changes: 37 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"extends": [ "airbnb" ],
"parser": "babel-eslint",
"env": {
"browser": true,
"node": true,
"jest": true
},
"plugins": [
"flowtype"
],
"rules": {
"semi": [ 2, "never" ],
"object-curly-newline": [ 0 ],
"object-property-newline": [ 0 ],
"comma-dangle": [ 0 ],
"react/jsx-filename-extension": [2, {
"extensions": [".js", ".jsx"]
}],
"import/no-extraneous-dependencies": [ 0 ],
"react/prop-types": [ 0 ],
"no-confusing-arrow": [ 0 ],
"no-underscore-dangle": [ 0 ],
"no-param-reassign": [ 0 ],
"react/forbid-prop-types": [ 0 ],
"no-plusplus": [ 0 ],
"guard-for-in": [ 0 ],
"no-restricted-syntax": [ 0 ],
"no-continue": [ 1 ],
"no-prototype-builtins": [ 0 ],
"max-len": [ 0, 80 ],
"no-mixed-operators": [ 0 ],
"no-lonely-if": [ 1 ],
"no-bitwise": [ 0 ],
"arrow-parens": [ 0 ]
}
}
7 changes: 7 additions & 0 deletions .flowconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[ignore]

# Disable module with broken flow types.
# .*/node_modules/babylon/*.*

[version]
^0.38.0
25 changes: 25 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# OS or Editor files
._*
.DS_Store
Thumbs.db

# Files that might appear on external disks
.Spotlight-V100
.Trashes

# Always-ignore extensions
*~
*.diff
*.err
*.log
*.orig
*.pyc
*.rej
*.sass-cache
*.sw?
*.vi

**/node_modules
**/es
**/coverage
**/lib
4 changes: 4 additions & 0 deletions .jshintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"esnext": true,
"asi": true
}
11 changes: 11 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
trailingComma: "es5",
singleQuote: true,
bracketSpacing: true,
jsxBracketSameLine: true,
parser: "babylon",
printWidth: 80,
tabWidth: 2,
useTabs: false,
semi: false
}
12 changes: 12 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
language: node_js
node_js:
- "5"
script:
- npm run check
addons:
code_climate:
repo_token: 923b8eea8dc288ced3fef24a6a878b84fb21af9f8e3332881460c963735e4590
after_script:
- codeclimate-test-reporter < coverage/lcov.info
notifications:
email: false
50 changes: 50 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"search.exclude": {
"# OS or Editor files": true,
"._*": true,
".DS_Store": true,
"Thumbs.db": true,
"# Files that might appear on external disks": true,
".Spotlight-V100": true,
".Trashes": true,
"# Always-ignore extensions": true,
"*~": true,
"*.diff": true,
"*.err": true,
"*.log": true,
"*.orig": true,
"*.pyc": true,
"*.rej": true,
"*.sass-cache": true,
"*.sw?": true,
"*.vi": true,
"**/node_modules": true,
"**/es": true,
"**/coverage": true,
"**/lib": true
},
"files.exclude": {
"# OS or Editor files": true,
"._*": true,
".DS_Store": true,
"Thumbs.db": true,
"# Files that might appear on external disks": true,
".Spotlight-V100": true,
".Trashes": true,
"# Always-ignore extensions": true,
"*~": true,
"*.diff": true,
"*.err": true,
"*.log": true,
"*.orig": true,
"*.pyc": true,
"*.rej": true,
"*.sass-cache": true,
"*.sw?": true,
"*.vi": true,
"**/node_modules": true,
"**/es": true,
"**/coverage": true,
"**/lib": true
}
}
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2017 Robin Frischmann

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
172 changes: 172 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
# Bredon

Bredon is a modern, specification-driven CSS value compiler in JavaScript.<br>
It's parser uses very detailed nodes and provides as much information as possible.<br>
The generated AST ([Abstract Syntax Tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree)) is simple and readable which allows efficient and straight-forward transormation. It automatically outputs formatted CSS values.

<img alt="TravisCI" src="https://travis-ci.org/rofrischmann/bredon.svg?branch=master"> <a href="https://codeclimate.com/github/rofrischmann/bredon/coverage"><img alt="Test Coverage" src="https://codeclimate.com/github/rofrischmann/bredon/badges/coverage.svg"></a> <img alt="npm downloads" src="https://img.shields.io/npm/dm/bredon.svg"> <img alt="gzipped size" src="https://img.shields.io/badge/gzipped-4.4kb-brightgreen.svg"> <img alt="npm version" src="https://badge.fury.io/js/bredon.svg"> <a href="https://gitter.im/rofrischmann/bredon"><img alt="Gitter" src="https://img.shields.io/gitter/room/rofrischmann/bredon.svg"></a>


## Support Us
Support Robin Frischmann's work on [Fela](https://github.com/rofrischmann/fela) and its ecosystem (Bredon) directly via [**Patreon**](https://www.patreon.com/rofrischmann).

Or support us on [**Open Collective**](https://opencollective.com/fela) to fund community work. This also includes Bredon as well.<br>
Thank you to all our backers!

<a href="https://opencollective.com/fela/backer/0/website?requireActive=false" target="_blank"><img src="https://opencollective.com/fela/backer/0/avatar.svg?requireActive=false"></a>
<a href="https://opencollective.com/fela/backer/1/website?requireActive=false" target="_blank"><img src="https://opencollective.com/fela/backer/1/avatar.svg?requireActive=false"></a>
<a href="https://opencollective.com/fela/backer/2/website?requireActive=false" target="_blank"><img src="https://opencollective.com/fela/backer/2/avatar.svg?requireActive=false"></a>
<a href="https://opencollective.com/fela/backer/3/website?requireActive=false" target="_blank"><img src="https://opencollective.com/fela/backer/3/avatar.svg?requireActive=false"></a>
<a href="https://opencollective.com/fela/backer/4/website?requireActive=false" target="_blank"><img src="https://opencollective.com/fela/backer/4/avatar.svg?requireActive=false"></a>
<a href="https://opencollective.com/fela/backer/5/website?requireActive=false" target="_blank"><img src="https://opencollective.com/fela/backer/5/avatar.svg?requireActive=false"></a>
<a href="https://opencollective.com/fela/backer/6/website?requireActive=false" target="_blank"><img src="https://opencollective.com/fela/backer/6/avatar.svg?requireActive=false"></a>
<a href="https://opencollective.com/fela/backer/7/website?requireActive=false" target="_blank"><img src="https://opencollective.com/fela/backer/7/avatar.svg?requireActive=false"></a>
<a href="https://opencollective.com/fela/backer/8/website?requireActive=false" target="_blank"><img src="https://opencollective.com/fela/backer/8/avatar.svg?requireActive=false"></a>
<a href="https://opencollective.com/fela/backer/9/website?requireActive=false" target="_blank"><img src="https://opencollective.com/fela/backer/9/avatar.svg?requireActive=false"></a>

## Installation
```sh
yarn add bredon
```
Alternatively use `npm i --save bredon`.

## Why?
I am heavily involved in the whole CSS in JS movement with [Fela](https://github.com/rofrischmann/fela) and [Elodin](https://github.com/rofrischmann/elodin) as well as [inline-style-prefixer](https://github.com/rofrischmann/inline-style-prefixer). While writing Elodin, a plugin-based style object linter, I struggled to do complex value validation and value transformation. As CSS values are just plain strings, we do not have any meaningful types.<br>
But, in order to perform efficient validation and transformation, we have to parse CSS values into useful type-aware components. That's where Bredon joins the game. It uses a specification-driven value parser that provides the required degree of accuracy and detail.

> Bredon also serves as a personal project to learn and understand how compilers work.
## How?
I heavily used [James Kyle](https://github.com/thejameskyle)'s [the-super-tiny-compiler](https://github.com/thejameskyle/the-super-tiny-compiler) to build Bredon. It follows the exact same steps as any other compiler does:

1. First of all we read the input, one by one, and generate tokens
2. Then we parse these tokens into syntactic nodes, also know as AST
3. *(optional)* We may now traverse the AST and transform nodes
4. Finally we generate a new CSS value using the transformed AST

## The Gist
```javascript
importparse, generate } from 'bredon'

const input = '10px solid rgba(255, 0, 255, 0.55)'
const ast = parse(input)

ast === {
type: 'ValueList',
body: [{
type: 'Value',
important: false,
body: [{
type: 'Dimension',
unit: 'px',
value: {
type: 'Integer',
negative: false,
value: 10
}
}, {
type: 'Identifier',
value: 'solid'
}, {
type: 'FunctionExpression',
callee: 'rgba',
params: [{
type: 'Integer',
negative: false,
value: 255
}, {
type: 'Integer',
negative: false,
value: 0
}, {
type: 'Integer',
negative: true,
value: 255
}, {
type: 'Float',
negative: false,
fractional: 0.55,
integer: 0,
}]
}]
}]
}

const output = generate(ast)

console.log(output)
// => 10px solid rgba(255, 0, 255, 0.55)

// parsing and generation can be combined
const output = compile(input)
```

## Documentation
* [**API Reference**](docs/API.md)
* bredon
* [parse](docs/api/bredon/parse.md)
* [traverse](docs/api/bredon/traverse.md)
* [generate](docs/api/bredon/generate.md)
* [compile](docs/api/bredon/compile.md)
* [types](docs/api/bredon/types.md)
* bredon-types
* [Validators](docs/api/bredon-types/Validators.md)
* [Builders](docs/api/bredon-types/Builders.md)
* bredon-validate
* [validate](docs/api/bredon-validate/validate.md)
* bredon-minify
* [minify](docs/api/bredon-minify/minify.md)
* [**AST Nodes**](docs/Nodes.md)
* [Identifier](docs/ASTNodes.md#identifier)
* [Operator](docs/ASTNodes.md#operator)
* [HexColor](docs/ASTNodes.md#hexcolor)
* [Parenthesis](docs/ASTNodes.md#parenthesis)
* [URL](docs/ASTNodes.md#url)
* [StringLiteral](docs/ASTNodes.md#stringliteral)
* [Assignment](docs/ASTNodes.md#assignment)
* [Dimension](docs/ASTNodes.md#dimension)
* [Integer](docs/ASTNodes.md#integer)
* [Float](docs/ASTNodes.md#float)
* [FunctionExpression](docs/ASTNodes.md#functionexpression)
* [Expression](docs/ASTNodes.md#expression)

## Plugins
Bredon's most powerful part is its extendable plugin system.<br>
Plugins are used to analyze and transform AST nodes.

| Plugin | Version | Size | Description |
| ------ | ------- | ---- | ----------- |
| [calc](packages/bredon-plugin-calc) | <img alt="npm version" src="https://badge.fury.io/js/bredon-plugin-calc.svg"> | <img alt="gzipped size" src="https://img.shields.io/badge/gzipped-8.6kb-brightgreen.svg"> | Precalculate calc() expression as much as possible |
| [case](packages/bredon-plugin-case) | <img alt="npm version" src="https://badge.fury.io/js/bredon-plugin-case.svg"> | <img alt="gzipped size" src="https://img.shields.io/badge/gzipped-0.31kb-brightgreen.svg"> | Normalize letter case for all identifiers |
| [color](packages/bredon-plugin-color) | <img alt="npm version" src="https://badge.fury.io/js/bredon-plugin-color.svg"> | <img alt="gzipped size" src="https://img.shields.io/badge/gzipped-7.9kb-brightgreen.svg"> | Manipulate, normalize and minify CSS color values |
| [initial](packages/bredon-plugin-initial) | <img alt="npm version" src="https://badge.fury.io/js/bredon-plugin-initial.svg"> | <img alt="gzipped size" src="https://img.shields.io/badge/gzipped-2.6kb-brightgreen.svg"> | Replace, normalize and minify initial values |
| [precision](packages/bredon-plugin-precision) | <img alt="npm version" src="https://badge.fury.io/js/bredon-plugin-precision.svg"> | <img alt="gzipped size" src="https://img.shields.io/badge/gzipped-0.27kb-brightgreen.svg"> | Normalize decimal number precision |
| [remove-unit](packages/bredon-plugin-remove-unit) | <img alt="npm version" src="https://badge.fury.io/js/bredon-plugin-remove-unit.svg"> | <img alt="gzipped size" src="https://img.shields.io/badge/gzipped-0.27kb-brightgreen.svg"> | Remove unnecessary value units |
| [trim-hex](packages/bredon-plugin-trim-hex) | <img alt="npm version" src="https://badge.fury.io/js/bredon-plugin-trim-hex.svg"> | <img alt="gzipped size" src="https://img.shields.io/badge/gzipped-0.21kb-brightgreen.svg"> | Minify hex color values if possible |
| [unit](packages/bredon-plugin-unit) | <img alt="npm version" src="https://badge.fury.io/js/bredon-plugin-unit.svg"> | <img alt="gzipped size" src="https://img.shields.io/badge/gzipped-0.73kb-brightgreen.svg"> | Convert, normalize and minify unit values |

## Integrations
To use Bredon within your project, you will need to somehow integrate the compiler into your workflow.<br>
Currently, we support to options to do so. You can either use Bredon with your existing CSS codebase using [PostCSS](http://postcss.org).
For JavaScript-based styling solutions (CSS in JS), there is [Elodin](https://github.com/rofrischmann/elodin) which can be configured to auto-fix styles.

* [elodin](https://github.com/rofrischmann/elodin)
* [postcss-bredon](packages/postcss-bredon)

### PostCSS Stand-Alones
You can also use [bredon-minify](packages/bredon-minify) and [bredon-validate](packages/bredon-validate) as a stand-alone plugin for PostCSS:

* [postcss-bredon-minify](packages/postcss-bredon-minify)
* [postcss-bredon-validate](packages/postcss-bredon-validate)

## Support
Join us on [Gitter](https://gitter.im/rofrischmann/bredon). <br>
We highly appreciate any contribution.<br>
We also love to get feedback.

## License
Bredon is licensed under the [MIT License](http://opensource.org/licenses/MIT).<br>
Documentation is licensed under [Creative Common License](http://creativecommons.org/licenses/by/4.0/).<br>
Created with ♥ by [@rofrischmann](http://rofrischmann.de).

<a target='_blank' rel='nofollow' href='https://app.codesponsor.io/link/pCQU3wY7qzomx7oGR27YYg5s/rofrischmann/bredon'> <img alt='Sponsor' width='888' height='68' src='https://app.codesponsor.io/embed/pCQU3wY7qzomx7oGR27YYg5s/rofrischmann/bredon.svg' /></a>
15 changes: 15 additions & 0 deletions modules/__tests__/arrayEach-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import arrayEach from '../arrayEach'

describe('arrayEach', () => {
it('should iterate an array', () => {
const iterator = jest.fn()

arrayEach([1, 2, 3, 4], iterator)

expect(iterator).toHaveBeenCalledTimes(4)
expect(iterator).toHaveBeenCalledWith(1, 0, 4, [1, 2, 3, 4])
expect(iterator).toHaveBeenCalledWith(2, 1, 4, [1, 2, 3, 4])
expect(iterator).toHaveBeenCalledWith(3, 2, 4, [1, 2, 3, 4])
expect(iterator).toHaveBeenCalledWith(4, 3, 4, [1, 2, 3, 4])
})
})
7 changes: 7 additions & 0 deletions modules/__tests__/arrayFilter-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import arrayFilter from '../arrayFilter'

describe('arrayFilter', () => {
it('should filter an array', () => {
expect(arrayFilter([1, 2, 3, 4], value => value > 2)).toEqual([3, 4])
})
})
7 changes: 7 additions & 0 deletions modules/__tests__/arrayMap-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import arrayMap from '../arrayMap'

describe('arrayMap', () => {
it('should map an array', () => {
expect(arrayMap([1, 2, 3], val => val * val)).toEqual([1, 4, 9])
})
})
Loading

0 comments on commit 5f56eaf

Please sign in to comment.