Skip to content

Commit 830ec16

Browse files
committed
feat(cssToJS): implemented plugin
1 parent 955870c commit 830ec16

File tree

11 files changed

+464
-138
lines changed

11 files changed

+464
-138
lines changed

.travis.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,3 @@ before_script:
1313
- npm prune
1414
script:
1515
- yarn lint && yarn test
16-
after_success:
17-
- yarn semantic-release

Readme.md

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,46 @@
1-
# javascript-plugin-boilerplate
2-
3-
> A boilerplate to write plugins in pure JavaScript using ES2015. Includes mocha, chai, prettier, husky, Rollup and Eslint
4-
5-
### Features
6-
* ES2015 support (using [rollup.js](http://rollupjs.org/) and [Babel](http://babeljs.io/))
7-
* [UMD](https://github.com/umdjs/umd) supported build
8-
* Automatic versioning using [semantic-release](https://github.com/semantic-release/semantic-release)
9-
* [Mocha](http://mochajs.org/) and [Chai](http://chaijs.com/) for testing
10-
* Lint using [babel-eslint](https://github.com/babel/babel-eslint)
11-
* Code coverage recording with [istanbul](https://gotwarlost.github.io/istanbul/)
12-
* Code coverage reporting to codecov.io
13-
* Prettier for code formatting as a precommit hook
14-
15-
## npm scripts
16-
- **test**: Run tests
17-
- **test:watch**: Run tests while watching at the same time
18-
- **test:cover**: Create code coverage report using istanbul
19-
- **test:report**: Report code coverage report to codecov.io
20-
- **build**: Build all JS files to different formats
21-
- **build:watch**: Build all JS files to different formats while watching
22-
- **lint**: Run eslint on all JS files
23-
- **lint:fix**: Fix linting errors
24-
- **format**: Run prettier on js files
1+
# transform css-to-js
2+
3+
> A utility to convert your CSS into JS or React Native compatible styles.
4+
5+
The online repl is available at https://transform.now.sh/css-to-js
6+
7+
### Installation
8+
```
9+
npm i transform-css-to-js
10+
```
11+
12+
### Usage
13+
14+
import cssToJS from "transform-css-to-js"
15+
16+
const css = `.main-wrapper {
17+
flex-direction: row;
18+
display: flex;
19+
flex: 1;
20+
}
21+
22+
#content {
23+
flex: 1;
24+
}
25+
26+
ul {
27+
padding: 20px 0;
28+
flex: 1;
29+
}
30+
31+
li {
32+
font-family:'Lato';
33+
color: whitesmoke;
34+
line-height: 44px;
35+
}`
36+
37+
const jsStyle = cssToJS(css)
38+
const reactNativeCompatibleCSS = cssToJS(css, true)
39+
```
40+
41+
### API
42+
43+
#### cssToJS(CSS, [supportReactNative])
2544
2645
## License
2746
MIT @ Ritesh Kumar

package.json

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"name": "javascript-plugin-boilerplate",
3-
"version": "0.0.0-semantically-released",
2+
"name": "transform-css-to-js",
3+
"version": "0.1.0",
44
"description": "A boilerplate to write plugins in pure JavaScript using ES2015",
55
"main": "dist/lunar.umd.js",
66
"module": "dist/lunar.es.js",
@@ -15,11 +15,9 @@
1515
"test:cover": "nyc ava",
1616
"test:report": "cat ./coverage/lcov.info | codecov && rm -rf ./coverage",
1717
"semantic-release": "semantic-release pre && npm publish && semantic-release post",
18-
"build": "npm run build:umd && npm run build:es && npm run build:cjs",
19-
"build:umd": "rollup -c rollup.umd.js",
20-
"build:es": "rollup -c rollup.es.js",
18+
"build": "npm run build:cjs",
2119
"build:cjs": "rollup -c rollup.cjs.js",
22-
"build:watch": "concurrently 'npm run build:umd -- -w' 'npm run build:es -- -w' 'npm run build:cjs -- -w'",
20+
"build:watch": "npm run build:cjs -- -w",
2321
"lint": "eslint src/**/*.js *.js tests/**/*.js",
2422
"lint:fix": "npm run lint -- -fix",
2523
"format": "prettier --write src/**/*.js *.js tests/**/*.js",
@@ -34,7 +32,6 @@
3432
"babel-preset-env": "^1.6.0",
3533
"babel-register": "^6.24.1",
3634
"codecov.io": "^0.1.6",
37-
"concurrently": "^3.5.0",
3835
"cz-conventional-changelog": "^2.0.0",
3936
"eslint": "^4.2.0",
4037
"eslint-config-prettier": "^2.3.0",
@@ -71,11 +68,16 @@
7168
"git add"
7269
]
7370
},
74-
"homepage": "https://github.com/ritz078/javascript-plugin-boilerplate",
71+
"homepage": "https://github.com/ritz078/transform-css-to-js",
7572
"ava": {
7673
"require": [
7774
"babel-register",
7875
"babel-polyfill"
7976
]
77+
},
78+
"dependencies": {
79+
"css-to-react-native": "^2.0.4",
80+
"lodash": "^4.17.4",
81+
"stringify-object": "^3.2.0"
8082
}
8183
}

rollup.cjs.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const banner = `/*
1313

1414
const config = {
1515
entry: "src/index.js",
16-
dest: "dist/lunar.cjs.js",
16+
dest: "dist/index.js",
1717
format: "cjs",
1818
banner,
1919
plugins: [fileSize()]

rollup.es.js

Lines changed: 0 additions & 12 deletions
This file was deleted.

rollup.umd.js

Lines changed: 0 additions & 16 deletions
This file was deleted.

src/index.js

Lines changed: 218 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,219 @@
1-
export default function(a, b) {
2-
return a + b;
1+
import cssToReactNative from "css-to-react-native";
2+
import kebabCase from "lodash/kebabCase";
3+
import stringify from "stringify-object";
4+
5+
const SPACE = " ";
6+
function toProperty(name) {
7+
if (name.charAt(0) === "-") name = name.slice(0);
8+
9+
return name.replace(/[^a-z0-9]([a-z0-9])?/gi, function(v, l) {
10+
if (l) return l.toUpperCase();
11+
return "";
12+
});
13+
}
14+
15+
function toSelectors(name) {
16+
const names = name.split(",");
17+
18+
return names.map(function(name) {
19+
name = name.trim();
20+
let newName = "";
21+
22+
if (name.charAt(0) === ".") {
23+
newName += "Class";
24+
name = name.slice(1);
25+
} else if (name.charAt(0) === "#") {
26+
newName += "Id";
27+
name = name.slice(1);
28+
} else {
29+
newName += "Element";
30+
}
31+
32+
return (
33+
name.replace(/([^a-z0-9])([a-z0-9])?/gi, function(v, c, l) {
34+
if (l)
35+
return c === "," || c === " " ? l.toLowerCase() : l.toUpperCase();
36+
return "";
37+
}) + newName
38+
);
39+
});
40+
}
41+
42+
function tokenizer(code) {
43+
const tokens = [];
44+
let token = "";
45+
const whitespc = ["\r\n", "\n\r", "\n", "\r"];
46+
let lastChar = "\0";
47+
let nextChar = "\0";
48+
let char = "\0";
49+
const specialChars = ["{", "}", ":", ";"];
50+
const specialCharsPB = ["{", "}", ";"];
51+
let sc = null;
52+
let inBrackets = false;
53+
54+
for (let i = 0; i < code.length; i++) {
55+
if (i) lastChar = code.charAt(i - 1);
56+
char = code.charAt(i);
57+
if (i + 1 < code.length) nextChar = code.charAt(i + 1);
58+
59+
if (~whitespc.indexOf(char) && ~whitespc.indexOf(lastChar)) {
60+
continue;
61+
}
62+
63+
sc = inBrackets ? specialChars : specialCharsPB;
64+
65+
if (~sc.indexOf(char)) {
66+
if (char === "{") inBrackets = true;
67+
if (char === "}") inBrackets = false;
68+
tokens.push(token);
69+
tokens.push(char);
70+
token = "";
71+
continue;
72+
}
73+
74+
token += char;
75+
}
76+
77+
if (token) tokens.push(token);
78+
79+
return tokens
80+
.map(function(token) {
81+
return token.trim();
82+
})
83+
.filter(function(token) {
84+
return token;
85+
});
86+
}
87+
88+
function convertoToJS(tokens) {
89+
const items = [];
90+
let actualItem = null;
91+
let actualProp = null;
92+
function readSelector(token) {
93+
const selectors = toSelectors(token);
94+
95+
actualItem = {
96+
originalValue: token,
97+
selectors: selectors,
98+
values: {}
99+
};
100+
101+
actualProp = null;
102+
items.push(actualItem);
103+
104+
return readBracketO;
105+
}
106+
107+
function readBracketO(token) {
108+
if (token !== "{") throw new Error("expected '{' ");
109+
110+
return readProperty;
111+
}
112+
113+
function readBracketC(token) {
114+
if (token !== "}") throw new Error("expected '}' ");
115+
return readSelector;
116+
}
117+
118+
function readDefinition(token) {
119+
if (token !== ":") throw new Error("expected ':' ");
120+
121+
return readValue;
122+
}
123+
124+
function readProperty(token) {
125+
if (token === "}") return readBracketC(token);
126+
127+
const property = toProperty(token);
128+
actualProp = property;
129+
130+
if (!actualItem.values[property]) {
131+
actualItem.values[property] = [];
132+
}
133+
134+
return readDefinition;
135+
}
136+
137+
function readValue(token) {
138+
actualItem.values[actualProp].push(token);
139+
140+
return readFinal;
141+
}
142+
143+
function readFinal(token) {
144+
if (token === "}") return readBracketC(token);
145+
if (token !== ";") throw new Error("expected ';' ");
146+
return readProperty;
147+
}
148+
149+
let nextAction = readSelector;
150+
let i = 0;
151+
tokens.forEach(function(token) {
152+
i++;
153+
nextAction = nextAction(token);
154+
});
155+
156+
return renderJS(items);
157+
}
158+
159+
function renderJS(items) {
160+
let objects = ["{"];
161+
objects = objects.concat(items.map(renderItem).join(","));
162+
objects.push("}");
163+
return objects.join("\n");
164+
}
165+
166+
function renderItem(item) {
167+
const code = ["\n //" + item.originalValue];
168+
169+
let properties = [];
170+
171+
for (const prop in item.values) {
172+
if (item.values.hasOwnProperty(prop)) {
173+
const propitem = {
174+
name: prop,
175+
value: item.values[prop][item.values[prop].length - 1]
176+
};
177+
let markup = '"';
178+
if (~propitem.value.indexOf('"')) {
179+
markup = "'";
180+
propitem.value = propitem.value.replace(/'/gi, "\\'");
181+
}
182+
properties.push(
183+
SPACE + SPACE + propitem.name + ": " + markup + propitem.value + markup
184+
);
185+
}
186+
}
187+
188+
properties = properties.map(function(x) {
189+
return SPACE + x;
190+
});
191+
192+
item.selectors.forEach(function(i) {
193+
code.push(SPACE + i + ": {");
194+
code.push(properties.join(",\n"));
195+
code.push(SPACE + "}");
196+
});
197+
198+
return code.join("\n");
199+
}
200+
201+
function getRnCode(css) {
202+
const styles = {};
203+
const code = eval("(" + convertoToJS(tokenizer(css)) + ")");
204+
Object.keys(code).forEach(key => {
205+
styles[key] = {};
206+
const arr = [];
207+
Object.keys(code[key]).forEach(key2 => {
208+
arr.push([kebabCase(key2), code[key][key2]]);
209+
});
210+
styles[key] = cssToReactNative(arr);
211+
});
212+
return stringify(styles, {
213+
indent: " "
214+
});
215+
}
216+
217+
export default function(code, reactNative = false) {
218+
return reactNative ? getRnCode(code) : convertoToJS(tokenizer(code));
3219
}

0 commit comments

Comments
 (0)