├── .gitignore
├── tests
├── results
│ ├── css
│ │ ├── header.absurd.css
│ │ └── index.absurd.css
│ ├── component
│ │ ├── widget.absurd.html
│ │ ├── widget.absurd.css
│ │ ├── share.absurd.html
│ │ └── share.absurd.css
│ ├── html
│ │ ├── page2.absurd.html
│ │ └── page.absurd.html
│ ├── compileComponent.absurd.html
│ ├── compileComponent.absurd.css
│ ├── compiledCSS.css
│ └── compiledHTML.html
└── data
│ ├── css
│ ├── header.css.js
│ ├── local.plugin.js
│ └── index.css.js
│ ├── html
│ ├── content.js
│ ├── page2.html.js
│ └── page.html.js
│ ├── global.plugin.js
│ └── component
│ ├── widget.component.js
│ └── share.component.js
├── .jshintrc
├── LICENSE-MIT
├── package.json
├── tasks
└── absurd.js
├── Gruntfile.js
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 | tmp
4 |
--------------------------------------------------------------------------------
/tests/results/css/header.absurd.css:
--------------------------------------------------------------------------------
1 | .header {
2 | marginTop: 20px;
3 | padding: 0;
4 | }
5 |
--------------------------------------------------------------------------------
/tests/results/component/widget.absurd.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/results/component/widget.absurd.css:
--------------------------------------------------------------------------------
1 | .social-widget {
2 | margin: 0;
3 | padding: 0;
4 | }
5 | .social-widget a {
6 | color: #000;
7 | }
8 |
--------------------------------------------------------------------------------
/tests/results/component/share.absurd.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | - Option A
4 | - Option B
5 |
6 |
--------------------------------------------------------------------------------
/tests/data/css/header.css.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.add({
3 | '.header': {
4 | marginTop: '20px',
5 | padding: 0
6 | }
7 | })
8 | }
--------------------------------------------------------------------------------
/tests/results/html/page2.absurd.html:
--------------------------------------------------------------------------------
1 |
2 | AbsurdJS is awesome
3 | Yes, it is ...
4 | Just anothe page
5 |
--------------------------------------------------------------------------------
/tests/results/component/share.absurd.css:
--------------------------------------------------------------------------------
1 | .share p {
2 | line-height: 20px;
3 | margin: 0;
4 | background: linear-gradient(to bottom, red, yellow, blue);
5 | }
6 |
--------------------------------------------------------------------------------
/tests/data/css/local.plugin.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.storage("mixin", function(px) {
3 | return {
4 | fontSize: px + 'px'
5 | }
6 | });
7 | }
8 |
--------------------------------------------------------------------------------
/tests/results/compileComponent.absurd.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/data/html/content.js:
--------------------------------------------------------------------------------
1 | module.exports = function() {
2 | return {
3 | '.content': {
4 | p: "Hello World!",
5 | 'a[href="http://krasimir.github.io/absurd/"]': 'Official AbsurdJS site'
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/tests/results/compileComponent.absurd.css:
--------------------------------------------------------------------------------
1 | .share p{line-height: 20px;background: linear-gradient(to bottom,red,yellow,blue);}.share p,.social-widget{margin: 0;}.social-widget{padding: 0;}.social-widget a{color: #000;}
--------------------------------------------------------------------------------
/tests/data/html/page2.html.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.add({
3 | header:{
4 | h1: "AbsurdJS is awesome",
5 | h2: "Yes, it is ...",
6 | p: "Just anothe page"
7 | }
8 | })
9 | }
10 |
--------------------------------------------------------------------------------
/tests/data/global.plugin.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.plugin('my-custom-gradient', function(api, colors) {
3 | return {
4 | background: 'linear-gradient(to bottom, ' + colors.join(", ") + ')'
5 | };
6 | });
7 | }
8 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "curly": true,
3 | "eqeqeq": true,
4 | "immed": true,
5 | "latedef": true,
6 | "newcap": true,
7 | "noarg": true,
8 | "sub": true,
9 | "undef": true,
10 | "boss": true,
11 | "eqnull": true,
12 | "node": true
13 | }
14 |
--------------------------------------------------------------------------------
/tests/data/html/page.html.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.add({
3 | body: {
4 | header:{
5 | h1: "AbsurdJS is awesome",
6 | h2: "Yes, it is ..."
7 | },
8 | 'section.container': require(__dirname + "/content.js")()
9 | }
10 | })
11 | }
12 |
--------------------------------------------------------------------------------
/tests/results/css/index.absurd.css:
--------------------------------------------------------------------------------
1 | body {
2 | width: 100%;
3 | height: 100%;
4 | margin: 0;
5 | padding: 0;
6 | background: linear-gradient(to bottom, red, yellow, blue);
7 | }
8 | .header {
9 | height: 100%;
10 | backgroundColor: white;
11 | fontSize: 18px;
12 | }
13 |
--------------------------------------------------------------------------------
/tests/results/compiledCSS.css:
--------------------------------------------------------------------------------
1 | .header {
2 | margin-top: 20px;
3 | background-color: white;
4 | font-size: 18px;
5 | }
6 | .header, body {
7 | padding: 0;
8 | height: 100%;
9 | }
10 | body {
11 | width: 100%;
12 | margin: 0;
13 | background: linear-gradient(to bottom, red, yellow, blue);
14 | }
15 |
--------------------------------------------------------------------------------
/tests/results/compiledHTML.html:
--------------------------------------------------------------------------------
1 | AbsurdJS is awesome
Yes, it is ...
AbsurdJS is awesome
Yes, it is ...
Just anothe page
--------------------------------------------------------------------------------
/tests/data/component/widget.component.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.add({
3 | css: {
4 | '.social-widget': {
5 | margin: 0,
6 | padding: 0,
7 | a: {
8 | color: '#000'
9 | }
10 | }
11 | },
12 | html: {
13 | '.social-widget': {
14 | p: "Spread the world.",
15 | a: "What's up"
16 | }
17 | }
18 | })
19 | }
--------------------------------------------------------------------------------
/tests/results/html/page.absurd.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | AbsurdJS is awesome
4 | Yes, it is ...
5 |
6 |
11 |
--------------------------------------------------------------------------------
/tests/data/css/index.css.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.add({
3 | body: {
4 | width: '100%',
5 | height: '100%',
6 | margin: 0,
7 | padding: 0,
8 | 'my-custom-gradient': ['red','yellow', 'blue']
9 | },
10 | '.header': [
11 | {
12 | height: '100%',
13 | backgroundColor: 'white'
14 | },
15 | api.storage('mixin')(18)
16 | ]
17 | });
18 | }
19 |
--------------------------------------------------------------------------------
/tests/data/component/share.component.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.add({
3 | css: {
4 | '.share': {
5 | p: {
6 | lineHeight: "20px",
7 | margin: 0,
8 | 'my-custom-gradient': ['red','yellow', 'blue']
9 | }
10 | }
11 | },
12 | html: {
13 | '.share': {
14 | ul: [
15 | { li: "Option A" },
16 | { li: "Option B" }
17 | ]
18 | }
19 | }
20 | })
21 | }
22 |
--------------------------------------------------------------------------------
/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013 Krasimir Tsonev
2 |
3 | Permission is hereby granted, free of charge, to any person
4 | obtaining a copy of this software and associated documentation
5 | files (the "Software"), to deal in the Software without
6 | restriction, including without limitation the rights to use,
7 | copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the
9 | Software is furnished to do so, subject to the following
10 | conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "grunt-absurd",
3 | "description": "Grunt plugin for AbsurdJS",
4 | "version": "0.1.0",
5 | "homepage": "https://github.com/krasimir/grunt-absurd.git",
6 | "author": {
7 | "name": "Krasimir Tsonev",
8 | "email": "krasimir@outset.ws",
9 | "url": "http://krasimirtsonev.com"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git@github.com:krasimir/grunt-absurd.git"
14 | },
15 | "bugs": {
16 | "url": "https://github.com/krasimir/grunt-absurd/issues"
17 | },
18 | "licenses": [
19 | {
20 | "type": "MIT",
21 | "url": "https://github.com/krasimir/grunt-absurd.git/blob/master/LICENSE-MIT"
22 | }
23 | ],
24 | "main": "Gruntfile.js",
25 | "engines": {
26 | "node": ">= 0.8.0"
27 | },
28 | "scripts": {
29 | "test": "grunt test"
30 | },
31 | "devDependencies": {
32 | "grunt-contrib-jshint": "~0.6.0",
33 | "grunt": "~0.4.1",
34 | "grunt-contrib-clean": "^0.5.0"
35 | },
36 | "peerDependencies": {
37 | "grunt": ">=0.4.0"
38 | },
39 | "dependencies": {
40 | "absurd": "*",
41 | "chalk": "^0.4.0"
42 | },
43 | "keywords": [
44 | "gruntplugin",
45 | "grunt",
46 | "absurd"
47 | ]
48 | }
49 |
--------------------------------------------------------------------------------
/tasks/absurd.js:
--------------------------------------------------------------------------------
1 | /*
2 | * grunt-absurd
3 | * https://github.com/krasimir/grunt-absurd.git
4 | *
5 | * Copyright (c) 2013 Krasimir Tsonev
6 | * Licensed under the MIT license.
7 | */
8 |
9 | 'use strict';
10 |
11 | module.exports = function(grunt) {
12 | var path = require('path'),
13 | chalk = require('chalk'),
14 | Absurd = require('absurd'),
15 | api;
16 |
17 | grunt.registerMultiTask('absurd', 'Grunt plugin for AbsurdJS', function() {
18 | // Merge task-specific and/or target-specific options with these defaults.
19 | var options = this.options({
20 | require: [],
21 | morph: null,
22 | combineSelectors: true,
23 | minify: false,
24 | keepCamelCase: false,
25 | extCSS: '.css',
26 | extHTML: '.html'
27 | });
28 |
29 | // Iterate over all src-dest file pairs
30 | this.files.forEach(function(f) {
31 | // validate src files
32 | var srcFiles = f.src.filter(function(filepath) {
33 | if (!grunt.file.exists(filepath)) {
34 | grunt.log.warn('Source file ' + chalk.cyan(filepath) + ' not found.');
35 | return false;
36 | } else {
37 | return true;
38 | }
39 | });
40 |
41 | if (srcFiles.length === 0) {
42 | grunt.log.warn('Destination ' + chalk.cyan(f.dest) + ' not written because src files were empty. ');
43 | return;
44 | }
45 |
46 | api = Absurd();
47 |
48 | api.morph(options.morph);
49 |
50 | if (options.require.length > 0) {
51 | api.import(grunt.file.expand(options.require).map(function(file){
52 | return path.resolve(file);
53 | }));
54 | }
55 |
56 | api.import(srcFiles.map(function(file){
57 | return path.resolve(file);
58 | }));
59 |
60 | api.compile(function(err,A,B) {
61 | if (err) {
62 | grunt.log.error('Absurd:' + err);
63 | return;
64 | }
65 |
66 | if (options.morph === 'component') {
67 | grunt.file.write(path.resolve(f.dest) + options.extCSS, A);
68 | grunt.verbose.writeln('File ' + chalk.cyan(f.dest + options.extCSS) + ' created.');
69 | grunt.file.write(path.resolve(f.dest) + options.extHTML, B);
70 | grunt.verbose.writeln('File ' + chalk.cyan(f.dest + options.extHTML) + ' created.');
71 | } else {
72 | grunt.file.write(path.resolve(f.dest), A);
73 | grunt.verbose.writeln('File ' + chalk.cyan(f.dest) + ' created.');
74 | }
75 | }, options);
76 | });
77 | });
78 | };
79 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 | // Project configuration.
3 | grunt.initConfig({
4 | testSrc: 'tests/data',
5 | testResult: 'tests/results',
6 |
7 | clean: ['<%= testResult %>'],
8 |
9 | absurd: {
10 | buildCSS: {
11 | options: {
12 | require: ['<%= testSrc %>/**/*.plugin.js'],
13 | minify: false,
14 | combineSelectors: false,
15 | keepCamelCase: true
16 | },
17 | expand: true,
18 | cwd: '<%= testSrc %>',
19 | src: ['**/*.css.js'],
20 | dest: '<%= testResult %>',
21 | ext: '.absurd.css'
22 | },
23 | compileCSS: {
24 | options: {
25 | require: ['<%= testSrc %>/**/*.plugin.js'],
26 | minify: false
27 | },
28 | src: ['<%= testSrc %>/**/*.css.js'],
29 | dest: '<%= testResult %>/compiledCSS.css',
30 | },
31 | buildHTML: {
32 | options: {
33 | minify: false,
34 | morph: 'html'
35 | },
36 | expand: true,
37 | cwd: '<%= testSrc %>/',
38 | src: ['**/*.html.js'],
39 | dest: '<%= testResult %>',
40 | ext: '.absurd.html'
41 | },
42 | compileHTML: {
43 | options: {
44 | minify: true,
45 | morph: 'html'
46 | },
47 | src: ['<%= testSrc %>/**/*.html.js'],
48 | dest: '<%= testResult %>/compiledHTML.html',
49 | },
50 | buildComponent: {
51 | options: {
52 | require: ['<%= testSrc %>/**/*.plugin.js'],
53 | minify: false,
54 | morph: 'component'
55 | },
56 | expand: true,
57 | cwd: '<%= testSrc %>/',
58 | src: ['**/*.component.js'],
59 | dest: '<%= testResult %>',
60 | ext: '.absurd'
61 | },
62 | compileComponent: {
63 | options: {
64 | require: ['<%= testSrc %>/**/*.plugin.js'],
65 | minify: true,
66 | morph: 'component'
67 | },
68 | src: ['<%= testSrc %>/**/*.component.js'],
69 | dest: '<%= testResult %>/compileComponent.absurd'
70 | }
71 | },
72 |
73 | jshint: {
74 | options: {
75 | curly: true,
76 | eqeqeq: true,
77 | immed: true,
78 | latedef: true,
79 | newcap: false,
80 | noarg: true,
81 | sub: true,
82 | undef: true,
83 | boss: true,
84 | eqnull: true,
85 | node: true,
86 | globals: {}
87 | },
88 |
89 | files: ['Gruntfile.js', 'tasks/**/*.js']
90 | }
91 | });
92 |
93 | // Load local tasks.
94 | grunt.loadTasks('tasks');
95 |
96 | grunt.loadNpmTasks('grunt-contrib-jshint');
97 | grunt.loadNpmTasks('grunt-contrib-clean');
98 |
99 | // Default task.
100 | grunt.registerTask('default', ['jshint', 'clean', 'absurd']);
101 | };
102 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # grunt-absurd
2 |
3 | > Grunt plugin for AbsurdJS ([https://github.com/krasimir/absurd](https://github.com/krasimir/absurd))
4 |
5 | ## Getting Started
6 | This plugin requires Grunt `~0.4.1`
7 |
8 | If you haven't used [Grunt](http://gruntjs.com/) before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to create a [Gruntfile](http://gruntjs.com/sample-gruntfile) as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:
9 |
10 | ```shell
11 | npm install grunt-absurd
12 | ```
13 |
14 | Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:
15 |
16 | ```js
17 | grunt.loadNpmTasks('grunt-absurd');
18 | ```
19 |
20 | ## The "absurd" task
21 |
22 | ### Overview
23 | In your project's Gruntfile, add a section named `absurd` to the data object passed into `grunt.initConfig()`.
24 |
25 | ```js
26 | grunt.initConfig({
27 | absurd: {
28 | task: {
29 | src: 'path to your .js file',
30 | dest: 'path to your .css file',
31 | options: {
32 | minify: true,
33 | }
34 | }
35 | },
36 | })
37 | ```
38 |
39 | ### Options
40 |
41 | #### require
42 |
43 | Type: `Array`
44 | Default: `[]`
45 |
46 | A list of files loaded before process the src files.
47 |
48 | #### extCSS
49 |
50 | Type: `String`
51 | Default: `'.css'`
52 |
53 | The css file extension used in the output of `morph: "component"`
54 |
55 | #### extHTML
56 |
57 | Type: `String`
58 | Default: `'.html'`
59 |
60 | The html file extension used in the output of `morph: "component"`
61 |
62 | #### Other Absurd Options
63 |
64 | ##### morph
65 |
66 | Type: `null | 'html' | 'component'`
67 | Default: `null`
68 |
69 | ##### combineSelectors
70 |
71 | Type: `Boolean`
72 | Default: `true`
73 |
74 | ##### minify
75 |
76 | Type: `Boolean`
77 | Default: `false`
78 |
79 | ##### keepCamelCase
80 |
81 | Type: `Boolean`
82 | Default: `false`
83 |
84 | ### Usage example
85 |
86 | ```js
87 | ...
88 | grunt.initConfig({
89 | testSrc: 'tests/data',
90 | testResult: 'tests/results',
91 |
92 | absurd: {
93 | buildCSS: {
94 | options: {
95 | require: ['<%= testSrc %>/**/*.plugin.js'],
96 | minify: false,
97 | combineSelectors: false,
98 | keepCamelCase: true
99 | },
100 | expand: true,
101 | cwd: '<%= testSrc %>',
102 | src: ['**/*.css.js'],
103 | dest: '<%= testResult %>',
104 | ext: '.absurd.css'
105 | },
106 | compileCSS: {
107 | options: {
108 | require: ['<%= testSrc %>/**/*.plugin.js'],
109 | minify: false
110 | },
111 | src: ['<%= testSrc %>/**/*.css.js'],
112 | dest: '<%= testResult %>/compiledCSS.css',
113 | },
114 | buildHTML: {
115 | options: {
116 | minify: false,
117 | morph: 'html'
118 | },
119 | expand: true,
120 | cwd: '<%= testSrc %>/',
121 | src: ['**/*.html.js'],
122 | dest: '<%= testResult %>',
123 | ext: '.absurd.html'
124 | },
125 | compileHTML: {
126 | options: {
127 | minify: true,
128 | morph: 'html'
129 | },
130 | src: ['<%= testSrc %>/**/*.html.js'],
131 | dest: '<%= testResult %>/compiledHTML.html',
132 | },
133 | buildComponent: {
134 | options: {
135 | require: ['<%= testSrc %>/**/*.plugin.js'],
136 | minify: false,
137 | morph: 'component'
138 | },
139 | expand: true,
140 | cwd: '<%= testSrc %>/',
141 | src: ['**/*.component.js'],
142 | dest: '<%= testResult %>',
143 | ext: '.absurd'
144 | },
145 | compileComponent: {
146 | options: {
147 | require: ['<%= testSrc %>/**/*.plugin.js'],
148 | minify: true,
149 | morph: 'component'
150 | },
151 | src: ['<%= testSrc %>/**/*.component.js'],
152 | dest: '<%= testResult %>/compileComponent.absurd'
153 | }
154 | },
155 | ...
156 | ```
157 |
158 | Use [dynamic_mappings](http://gruntjs.com/configuring-tasks#building-the-files-object-dynamically) to create separate output files. use `static_mappings` to create single output file.
159 |
--------------------------------------------------------------------------------