Skip to content

Commit 858b617

Browse files
v0.1.0
1 parent 5bac080 commit 858b617

File tree

8 files changed

+894
-0
lines changed

8 files changed

+894
-0
lines changed

bin/index.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
var nativeCss = require('../lib/index.js');
2+
3+
// var argv = process.argv,
4+
// _input = argv[2] === '-i' ? true : false,
5+
// _filePath = argv[3];
6+
7+
// if (!_input) {
8+
// console.log("please input source file");
9+
// return false;
10+
// }
11+
12+
13+
// console.log(nativeCss.convert(_filePath))
14+
15+
module.exports = nativeCss;

index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = require('./bin/index.js');

lib/index.js

Lines changed: 364 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,364 @@
1+
var _ = require('./utils'),
2+
_cssParse = require('css-parse'),
3+
// 不支持属性的正则
4+
_unsupportedRegExp = new RegExp('^(display)|(transtion)|(background-[^c])|(box-sizing)', 'g'),
5+
6+
// transform- 的正则
7+
_transformRegExp = new RegExp('transform-\s*', 'g'),
8+
9+
// border 的正则
10+
_borderRegExp = new RegExp('^border(\-\s+){0,2}', 'g'),
11+
12+
// text-decoration for text-decoration-line
13+
_textDecorationRegExp = new RegExp('(text-decoration)', 'g');
14+
15+
16+
/**
17+
* NativeCss 构造函数
18+
* @method NativeCss
19+
*/
20+
var NativeCss = function () {
21+
this._css = null;
22+
this._rules = null;
23+
};
24+
25+
/**
26+
* 打开文件,并获取文件内容
27+
* @method open
28+
* @param {[type]} filePath [description]
29+
* @return {[type]} [description]
30+
*/
31+
NativeCss.prototype._open = function (filePath) {
32+
this._css = _.readFile(filePath);
33+
return this;
34+
}
35+
36+
/**
37+
* 将css文件中的内容通过 css-parse 转为对象
38+
* @method toObject
39+
* @return {[type]} [description]
40+
*/
41+
NativeCss.prototype._toObject = function () {
42+
43+
this._css = _cssParse(this._css);
44+
45+
// stylesheet.rules => []
46+
47+
return this;
48+
}
49+
50+
/**
51+
* 获取 css 对象的 stylesheet 属性
52+
* @method _getCssStyles
53+
* @return {[type]} [description]
54+
*/
55+
NativeCss.prototype._getCssStyles = function () {
56+
return this._css.stylesheet.rules;
57+
}
58+
59+
/**
60+
* 过滤、清洗属性
61+
* @method _filterProperty
62+
* @param {[type]} propertyName [description]
63+
* @return {[type]} [description]
64+
*/
65+
NativeCss.prototype._filterProperty = function (propertyName) {
66+
let _res = {
67+
key: propertyName,
68+
value: _.toCamelCase(propertyName)
69+
};
70+
71+
// display
72+
if (_unsupportedRegExp.test(propertyName)) {
73+
return false;
74+
}
75+
76+
// transform
77+
if (_transformRegExp.test(propertyName)) {
78+
return false;
79+
}
80+
81+
// text-decoration
82+
if (_textDecorationRegExp.test(propertyName)) {
83+
_res.value += 'Line';
84+
}
85+
86+
// border
87+
if (_borderRegExp.test(propertyName)) {
88+
_res['key'] = 'border';
89+
90+
const _borderArr = propertyName.split('-');
91+
92+
if (_borderArr.length === 1) {
93+
_res.value = [
94+
`${propertyName}Style`,
95+
`${propertyName}Width`,
96+
`${propertyName}Color`,
97+
]
98+
} else if (_borderArr.length === 2) {
99+
const _propertyName = _.toCamelCase(propertyName);
100+
101+
_res.value = _res.value === 'borderRadius' ?
102+
[ _res.value ] :
103+
[
104+
`${_propertyName}Style`,
105+
`${_propertyName}Width`,
106+
`${_propertyName}Color`,
107+
];
108+
109+
} else {
110+
_res.value = [ _res.value ];
111+
}
112+
}
113+
114+
return _res;
115+
}
116+
117+
/**
118+
* 过滤、清洗数字类型的值(处理 px/rem/em)
119+
* @method _filterValueNum
120+
* @param {[type]} valueNum [description]
121+
* @return {[type]} [description]
122+
*/
123+
NativeCss.prototype._filterValueNum = function (valueNum) {
124+
return _.filterValueToNum(valueNum);
125+
}
126+
127+
/**
128+
* 判断属性值是否是混合型
129+
* @method _isMixedValue
130+
* @param {[type]} mixedValue [description]
131+
* @return {Boolean} [description]
132+
*/
133+
NativeCss.prototype._isMixedValue = function (mixedValue) {
134+
return mixedValue.indexOf(' ') !== -1;
135+
}
136+
137+
/**
138+
* 处理混合类型的值,如 margin / padding / border
139+
* @method _filterValueMixed
140+
* @param {[type]} valueMixed [description]
141+
* @return {[type]} [description]
142+
*/
143+
NativeCss.prototype._filterValueMixed = function (property, valueMixed) {
144+
145+
switch(property.key) {
146+
case 'margin':
147+
return this._boxTransfer(property.key, valueMixed);
148+
case 'padding':
149+
return this._boxTransfer(property.key, valueMixed);
150+
case 'transform':
151+
return this._transformTransfer(valueMixed);
152+
case 'border':
153+
return this._borderTransfer(property.value, valueMixed);
154+
// default:
155+
// return valueMixed;
156+
}
157+
}
158+
159+
/**
160+
* 对 margin / padding 属性进行转换为 top / right / bottom / left
161+
* @method _boxTransfer
162+
* @param {[type]} propertyName [description]
163+
* @param {[type]} value [description]
164+
* @return {[type]} [description]
165+
*/
166+
NativeCss.prototype._boxTransfer = function (propertyName, value) {
167+
const _arr = value.split(' '),
168+
const _arrLen = _arr.length;
169+
170+
if (_arrLen === 1) {
171+
return {
172+
[`${propertyName}`]: _arr[0]
173+
};
174+
} else if (_arrLen === 2) {
175+
return {
176+
[`${propertyName}Top`]: _arr[0],
177+
[`${propertyName}Right`]: _arr[1],
178+
[`${propertyName}Bottom`]: _arr[0],
179+
[`${propertyName}Left`]: _arr[1],
180+
};
181+
} else if (_arrLen === 3) {
182+
return {
183+
[`${propertyName}Top`]: _arr[0],
184+
[`${propertyName}Right`]: _arr[1],
185+
[`${propertyName}Bottom`]: _arr[2],
186+
[`${propertyName}Left`]: _arr[1],
187+
};
188+
} else if (_arrLen === 4) {
189+
return {
190+
[`${propertyName}Top`]: _arr[0],
191+
[`${propertyName}Right`]: _arr[1],
192+
[`${propertyName}Bottom`]: _arr[2],
193+
[`${propertyName}Left`]: _arr[3],
194+
};
195+
}
196+
};
197+
198+
/**
199+
* 属性 transform 的转换器
200+
* @method _transformTransfer
201+
* @param {[type]} value [description]
202+
* @return {[type]} [description]
203+
*/
204+
NativeCss.prototype._transformTransfer = function (value) {
205+
const _value = value.split(' ');
206+
const _transform = _value.reduce( (acc, cur) => {
207+
208+
return acc.concat(this._transformItemTransfer(cur));
209+
210+
}, []);
211+
212+
return {
213+
transform: _transform
214+
}
215+
}
216+
217+
/**
218+
* 属性 transform item 的转换器
219+
* @method _transformItemTransfer
220+
* @param {[type]} value [description]
221+
* @return {[type]} [description]
222+
*/
223+
NativeCss.prototype._transformItemTransfer = function (value) {
224+
const _transformItem = value.replace(/(\w*)(?:\()(.*)(?:\))/g, (_, a, b) => {
225+
226+
const _bArr = b.split(',');
227+
const _bLen = _bArr.length;
228+
229+
if (_bLen === 1) {
230+
if (a.indexOf('X') === -1) {
231+
a += 'X';
232+
}
233+
234+
return JSON.stringify([
235+
{[`${a}`]: _bArr[0]}
236+
]);
237+
} else if (_bLen === 2) {
238+
return JSON.stringify([
239+
{[`${a}X`]: _bArr[0]},
240+
{[`${a}Y`]: _bArr[1]},
241+
]);
242+
} else if (_bLen === 3) {
243+
return JSON.stringify([
244+
{[`${a}X`]: _bArr[0]},
245+
{[`${a}Y`]: _bArr[1]},
246+
{[`${a}Z`]: _bArr[2]},
247+
]);
248+
}
249+
});
250+
251+
return JSON.parse(_transformItem)
252+
}
253+
254+
/**
255+
* 属性 border 转换器
256+
* @method _borderTransfer
257+
* @param {[type]} propertyName [description]
258+
* @param {[type]} value [description]
259+
* @return {[type]} [description]
260+
*/
261+
NativeCss.prototype._borderTransfer = function (propertyName, value) {
262+
const _value = value.split(' ');
263+
264+
const _propertyValue = _value.reduce( (acc, cur) => {
265+
266+
if (_.isColor(cur)) {
267+
acc['color'] = cur;
268+
} else if (_.isNumber(cur)) {
269+
acc['number'] = cur;
270+
} else {
271+
acc['style'] = cur;
272+
}
273+
274+
return acc;
275+
}, {});
276+
277+
return propertyName.reduce( (acc, cur) => {
278+
279+
let _v = null;
280+
281+
if (cur.indexOf('Style') !== -1) {
282+
_v = _propertyValue['style'];
283+
} else if (cur.indexOf('Color') !== -1) {
284+
_v = _propertyValue['color'];
285+
} else {
286+
_v = _propertyValue['number'];
287+
}
288+
289+
acc[cur] = _v;
290+
291+
return acc;
292+
293+
}, {});
294+
}
295+
296+
/**
297+
* 对 css 的属性进行转换
298+
* @method convert
299+
* @param {[type]} filePath [description]
300+
* @return {[type]} [description]
301+
*/
302+
NativeCss.prototype.convert = function (filePath) {
303+
304+
this._rules = this._open(filePath)
305+
._toObject()
306+
._getCssStyles();
307+
308+
let _cssObj = {};
309+
310+
this._rules.map( item => {
311+
if(item.hasOwnProperty('type') &&
312+
item.hasOwnProperty('selectors')) {
313+
314+
item.selectors.map( selector => {
315+
316+
const key = _.cssNameTransfer(selector);
317+
const value = item.declarations.reduce( (acc, cur) => {
318+
319+
let _property = this._filterProperty(cur.property);
320+
321+
if (_property) {
322+
323+
// 根据值得特点来判定属性的类型
324+
if (this._isMixedValue(cur.value)) {
325+
326+
const _propertyValue = this._filterValueMixed(_property,
327+
this._filterValueNum(cur.value));
328+
329+
acc = Object.assign({}, acc, _propertyValue);
330+
331+
} else {
332+
acc[_property.value] = this._filterValueNum(cur.value);
333+
}
334+
}
335+
336+
return acc;
337+
338+
}, {});
339+
340+
_cssObj = Object.assign({}, _cssObj, {
341+
[key]: value
342+
})
343+
344+
});
345+
}
346+
});
347+
348+
return _cssObj;
349+
}
350+
351+
if(typeof exports == 'object') {
352+
module.exports = new NativeCss();
353+
} else if ( typeof define == 'function' && define.amd ) {
354+
define([], function(){ return new NativeCss() })
355+
} else {
356+
window.NativeCss = new NativeCss()
357+
}
358+
359+
360+
361+
362+
363+
364+

0 commit comments

Comments
 (0)