-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support import options #4
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
// | ||
// # Import | ||
// | ||
// Subsitute `@import { file: filename; }` with the contents of `filename`. | ||
// | ||
|
||
/*jslint node: true */ | ||
"use strict"; | ||
|
||
var fs = require('fs'); | ||
var path = require('path'); | ||
var whitespace = require('css-whitespace'); | ||
var rework = require('rework'); | ||
|
||
// | ||
// ## Register plugin | ||
// | ||
// * **opts**, options object. May contain the following: | ||
// | ||
// * path: base path for resolving imports. | ||
// * whitespace: boolean, set to true if imported files use significant | ||
// whitespace instead of curlies. | ||
// | ||
module.exports = function (opts) { | ||
return function (style) { | ||
return new Import(opts).visit(style); | ||
}; | ||
}; | ||
|
||
// | ||
// ## Importer | ||
// | ||
function Import(opts) { | ||
if(!opts.base) { | ||
throw new Error("Must specify a file path"); | ||
} | ||
|
||
opts = opts || {}; | ||
this.opts = opts; | ||
this.base = opts.base || process.cwd(); | ||
this.path = opts.path; | ||
this.visit = this.visit.bind(this); | ||
this.importFile = this.importFile.bind(this); | ||
this.map = opts.map || []; | ||
this.target = opts.target; | ||
|
||
// is relative? | ||
if(path.resolve(this.path) !== this.path) { | ||
this.path = path.resolve(this.base, this.path); | ||
} | ||
} | ||
|
||
Import.prototype.visit = function (node, index, arr) { | ||
if (!node) return; | ||
var type = node.type || 'stylesheet'; | ||
if (!this[type]) return; | ||
this[type](node, index, arr); | ||
}; | ||
|
||
Import.prototype.stylesheet = function (stylesheet) { | ||
for (var i = stylesheet.rules.length; i >= 0; i-=1) { | ||
this.visit(stylesheet.rules[i], i, stylesheet.rules); | ||
} | ||
}; | ||
|
||
Import.prototype.import = function (node, index, arr) { | ||
var regex = /url\(['"]?(.*?)['"]?\)/; | ||
var filename = node.import.match(regex); | ||
if (filename && filename[1] && !isUrl(filename[1])) { | ||
if(this.target) { | ||
// /(\w+)_(common|target)\.\w+/ | ||
var targetRegex = new RegExp('(\\w+)_(' + this.target.join('|') + ')\\.\\w+'); | ||
var matchTarget = filename[1].match(targetRegex); | ||
if(!matchTarget) { | ||
arr.splice(index, 1); | ||
return; | ||
} | ||
} | ||
|
||
var ast = this.parseFile(filename[1]); | ||
var i = 0; | ||
arr.splice(index, 1); | ||
|
||
ast.rules.forEach(function (rule) { | ||
arr.splice(0 + i + index, 0, rule); | ||
i++; | ||
}); | ||
} | ||
}; | ||
|
||
Import.prototype.rule = function (rule, index, base) { | ||
if (rule.selectors[0] == '@import') { | ||
var ast = rule.declarations.map(this.importFile); | ||
var rules = []; | ||
ast.filter(function (item) { | ||
return !!item; | ||
}).forEach(function (item) { | ||
rules = rules.concat(item.rules); | ||
}); | ||
|
||
var removed = base.splice(index, 1); | ||
// Insert rules at same index | ||
var i = 0; // To make imports in order. | ||
rules.forEach(function (rule) { | ||
var removed = base.splice(index + i, 0, rule); | ||
i++; | ||
}); | ||
} | ||
}; | ||
|
||
Import.prototype.importFile = function (declaration) { | ||
if (declaration.property !== 'file') return; | ||
return this.parseFile(declaration.value); | ||
}; | ||
|
||
Import.prototype.parseFile = function (file) { | ||
var load; | ||
//is absolute? | ||
if(path.resolve(file) === file) { | ||
load = path.join(this.base, file); | ||
} else { | ||
load = path.resolve(path.dirname(this.path), file); | ||
} | ||
|
||
// Skip circular imports. | ||
if (this.map.indexOf(load) !== -1) { | ||
return false; | ||
} | ||
var data = fs.readFileSync(load, this.opts.encoding || 'utf8'); | ||
|
||
if (this.opts.whitespace) { | ||
data = whitespace(data); | ||
} | ||
|
||
this.map.push(load); | ||
// Create AST and look for imports in imported code. | ||
var opts = { | ||
whitespace: this.opts.whitespace, | ||
map: this.map, | ||
base: this.base, | ||
path: load | ||
}; | ||
|
||
var ast = rework(data).use(module.exports(opts)); | ||
return ast.obj.stylesheet; | ||
}; | ||
|
||
|
||
function isUrl(url) { | ||
return (/^([\w]+:)?\/\/./).test(url); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ var rework = require('rework'); | |
var calc = require('rework-calc'); | ||
var hex = require('rework-hex-alpha'); | ||
var vars = require('rework-vars')(); | ||
var imprt = require('rework-importer'); | ||
var imprt = require('./import.js'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please also remove the 'rework-importer' definition in package.json |
||
var path = require('path'); | ||
|
||
/** | ||
|
@@ -22,30 +22,29 @@ module.exports = provecss; | |
*/ | ||
|
||
function provecss (string, options) { | ||
var browsers; | ||
var import_path, import_base; | ||
if(options && options.browsers) { | ||
browsers = options.browsers; | ||
} | ||
if(options && options.path) { | ||
import_path = path.basename(options.path); | ||
if(!options.base) { | ||
import_base = path.dirname(options.path); | ||
} else { | ||
import_base = options.base; | ||
} | ||
options = options || {}; | ||
this.browsers = options.browsers; | ||
if(options.path) { | ||
this.import_path = path.basename(options.path); | ||
this.import_base = options.base || path.dirname(options.path); | ||
} | ||
this.layout_target = options.target; | ||
|
||
//not run autoprefixer by default | ||
if(browsers) { | ||
string = prefixes(browsers).process(string).css; | ||
if(this.browsers) { | ||
string = prefixes(this.browsers).process(string).css; | ||
} | ||
if(import_path) { | ||
string = rework(string) | ||
.use(imprt({ | ||
path: import_path, | ||
base: import_base | ||
})).toString(); | ||
|
||
//handle import inlining if any | ||
if(this.import_path) { | ||
var opts = { | ||
path: this.import_path, | ||
base: this.import_base, | ||
target: this.layout_target | ||
}; | ||
string = rework(string).use(imprt(opts)).toString(); | ||
} | ||
|
||
return rework(string, options) | ||
.use(vars) | ||
.use(hex) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
@import url("imprt_core.css"); | ||
@import url("imprt_large.css"); | ||
@import url("imprt_large.css"); | ||
@import url("imprt_xlarge.css"); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
headers { | ||
background-color: orange; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,4 +2,4 @@ | |
headers { | ||
background-color: black; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
headers { | ||
background-color: orange; | ||
} | ||
|
||
@media (min-width: 768px) { | ||
headers { | ||
background-color: black; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
@media (min-width: 1024px) { | ||
headers { | ||
background-color: red; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
headers { | ||
background-color: orange; | ||
} | ||
|
||
@media (min-width: 1024px) { | ||
headers { | ||
background-color: red; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,7 +45,7 @@ describe('@import inlining feature', function () { | |
{path:"test/features/imprt.css"}).trim(), | ||
output.trim()); | ||
}); | ||
|
||
it('should add base option support', function () { | ||
var input = read('features/imprt'); | ||
var output = read('features/imprt.out'); | ||
|
@@ -56,6 +56,47 @@ describe('@import inlining feature', function () { | |
}).trim(), | ||
output.trim()); | ||
}); | ||
|
||
it('should generate css based on target option (core)', function () { | ||
var input = read('features/imprt'); | ||
var output = read('features/imprt_core.out'); | ||
var option = { | ||
path: 'test/features/imprt.css', | ||
target: ['core'] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. was an proposal to rework-importer simme/rework-importer#8 |
||
}; | ||
assert.equal(provecss(input, option).trim(), output.trim()); | ||
}); | ||
|
||
it('should generate css based on target option (core+large)', function () { | ||
var input = read('features/imprt'); | ||
var output = read('features/imprt_large.out'); | ||
var option = { | ||
path: 'test/features/imprt.css', | ||
target: ['core', 'large'] | ||
}; | ||
assert.equal(provecss(input, option).trim(), output.trim()); | ||
}); | ||
|
||
it('should generate css based on target option (core+xlarge)', function () { | ||
var input = read('features/imprt'); | ||
var output = read('features/imprt_xlarge.out'); | ||
var option = { | ||
path: 'test/features/imprt.css', | ||
target: ['core', 'xlarge'] | ||
}; | ||
assert.equal(provecss(input, option).trim(), output.trim()); | ||
}); | ||
|
||
it('should generate css based on target option (core+large+xlarge)', function () { | ||
var input = read('features/imprt'); | ||
var output = read('features/imprt.out'); | ||
var option = { | ||
path: 'test/features/imprt.css', | ||
target: ['core', 'large' , 'xlarge'] | ||
}; | ||
assert.equal(provecss(input, option).trim(), output.trim()); | ||
}); | ||
|
||
}); | ||
|
||
/** | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no decision here.
Besides
_layout
style, is it reasonable to also accept.layout
style such asimprt.large.css
,skin.default.css
?