-
Notifications
You must be signed in to change notification settings - Fork 8
/
index.js
134 lines (103 loc) · 3.63 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// builtin
var fs = require('fs');
var path = require('path');
// vendor
var resolve = require('resolve');
var cssp = require('cssp');
var traverse = require('traverse');
// local
var prefix = require('./lib/prefix');
// replace nodes with tree
// nodes is an array representing a node
function replace(nodes, tree) {
// truncate previous nodes
nodes.splice(0, nodes.length);
// insert tree as new nodes
tree.forEach(function(node) {
nodes.push(node);
});
}
// flatten @imports given a basepath, and a tree
// inline all of the import statements into the tree
// @return a tree with all statements inlined
function flatten(file, modules) {
var src = fs.readFileSync(file, 'utf8');
var base = path.dirname(file);
var tree = cssp.parse(src);
traverse(tree).forEach(function (node) {
var self = this;
if (node !== 'atrules') {
return;
}
node = this.parent.node;
// ignore non import
if (node[1][0] !== 'atkeyword' && nodes[1][1][0] !== 'ident' &&
node[1][1][1] !== 'import') {
return;
}
// ignore non string imports
if (node[3][0] !== 'string') {
return;
}
// remove quotes from imported name
var name = node[3][1].replace(/["']/g, '');
// @import "module"
if (name[0] !== '.') {
// if user uses direct path to css file in module
// we pluck the module name from the path start
var pkg_name = name.split('/', 1)[0];
// lookup the entry css file
var filepath = resolve.sync(name, {
basedir: base,
extensions: ['.css'],
packageFilter: function (pkg) {
pkg_name = pkg.name;
pkg.main = pkg.style;
return pkg;
}
});
if (modules.indexOf(filepath) !== -1) {
return;
}
modules.push(filepath);
// run css file through tree -> flatten -> prefix
// get required module as a css tree
// replace @import node with new tree
return replace(self.parent.node,
prefix(pkg_name, flatten(filepath, modules)));
}
var filepath = path.join(base, name);
if (modules.indexOf(filepath) !== -1) {
return;
}
modules.push(filepath);
// path is a file
if (fs.statSync(filepath).isFile()) {
return replace(self.parent.node, flatten(filepath, modules));
}
// path is a dir
var pkginfo = path.join(filepath, 'package.json');
// package.json exists for path
// use style info and prefix
if (fs.existsSync(pkginfo)) {
var info = JSON.parse(fs.readFileSync(pkginfo));
filepath = path.join(base, name, info.style || 'index.css')
return replace(self.parent.node,
prefix(info.name, flatten(filepath, modules)));
}
// no package.json, try index.css in the dir
filepath = path.join(filepath, 'index.css');
// do not prefix if just loading index.css from a dir
// allows for easier organization of multi css files without prefixing
if (fs.existsSync(filepath)) {
return replace(self.parent.node,
flatten(filepath, modules));
}
});
return tree;
}
// process given file for // @require statements
// file should be /full/path/to/file.css
module.exports = function(file) {
return cssp.translate(flatten(file, []));
};