* Adds better non-adjacent selector merging when body is the same.
* Fixed issue [#158](https://github.com/GoalSmashers/clean-css/issues/158) - adds body-based selectors reduction.
* Fixed issue [#182](https://github.com/GoalSmashers/clean-css/issues/182) - removing space after closing brace.
+* Fixed issue [#351](https://github.com/GoalSmashers/clean-css/issues/351) - remote `@import`s after content.
* Fixed issue [#357](https://github.com/GoalSmashers/clean-css/issues/357) - non-standard but valid URLs.
* Fixed issue [#416](https://github.com/GoalSmashers/clean-css/issues/416) - accepts hash as `minify` argument.
var nextEnd = 0;
var cursor = 0;
var isComment = commentScanner(data);
- var afterContent = contentScanner(data);
for (; nextEnd < data.length;) {
nextStart = nextImportAt(data, cursor);
break;
}
- context.done.push(data.substring(0, nextStart));
+ var noImportPart = data.substring(0, nextStart);
+ context.done.push(noImportPart);
context.left.unshift([data.substring(nextEnd + 1), context]);
-
- return afterContent(nextStart) ?
- processNext(context) :
- inline(data, nextStart, nextEnd, context);
+ context.afterContent = hasContent(noImportPart);
+ return inline(data, nextStart, nextEnd, context);
}
// no @import matched in current data
};
}
-function contentScanner(data) {
+function hasContent(data) {
var isComment = commentScanner(data);
var firstContentIdx = -1;
while (true) {
break;
}
- return function(idx) {
- return firstContentIdx > -1 ?
- idx > firstContentIdx :
- false;
- };
+ return firstContentIdx > -1;
}
function inline(data, nextStart, nextEnd, context) {
var isRemote = context.isRemote || REMOTE_RESOURCE.test(importedFile);
if (context.localOnly && isRemote) {
- context.warnings.push('Ignoring remote @import declaration of "' + importedFile + '" as no callback given.');
- restoreImport(importedFile, mediaQuery, context);
+ if (context.afterContent || hasContent(context.done.join('')))
+ context.warnings.push('Ignoring remote @import of "' + importedFile + '" as no callback given.');
+ else
+ restoreImport(importedFile, mediaQuery, context);
+
+ return processNext(context);
+ }
+ if (!isRemote && context.afterContent) {
+ context.warnings.push('Ignoring local @import of "' + importedFile + '" as after other CSS content.');
return processNext(context);
}
--- /dev/null
+@import url(http://jakubpawlowicz.com/styles.css);
'with double underscore': [
'@import url(test/fixtures/partials/with__double_underscore.css);',
'.one{color:green}'
+ ],
+ 'remote inside local': [
+ '@import url(test/fixtures/partials/remote.css);',
+ '@import url(http://jakubpawlowicz.com/styles.css);'
+ ],
+ 'remote inside local after content': [
+ 'a{color:red}@import url(test/fixtures/partials/remote.css);',
+ 'a{color:red}'
+ ],
+ 'remote inside local after imported content': [
+ '@import url(test/fixtures/partials/one.css);@import url(test/fixtures/partials/remote.css);',
+ '.one{color:red}'
]
}, { root: process.cwd() }),
'malformed but still valid @import': cssContext({
});
}
},
+ 'external imports and no callback': {
+ 'without content': {
+ 'topic': function () {
+ return new CleanCSS().minify('@import url(http://jakubpawlowicz.com/styles.css);');
+ },
+ 'has right output': function (minified) {
+ assert.equal(minified.styles, '@import url(http://jakubpawlowicz.com/styles.css);');
+ },
+ 'has no errors': function (minified) {
+ assert.isEmpty(minified.errors);
+ },
+ 'has a warning': function (minified) {
+ assert.deepEqual(minified.warnings, []);
+ }
+ },
+ 'after content': {
+ 'topic': function () {
+ return new CleanCSS().minify('a{color:red}@import url(http://jakubpawlowicz.com/styles.css);');
+ },
+ 'has right output': function (minified) {
+ assert.equal(minified.styles, 'a{color:red}');
+ },
+ 'has no errors': function (minified) {
+ assert.isEmpty(minified.errors);
+ },
+ 'has a warning': function (minified) {
+ assert.deepEqual(minified.warnings, ['Ignoring remote @import of "http://jakubpawlowicz.com/styles.css" as no callback given.']);
+ }
+ },
+ 'after local import': {
+ 'topic': function () {
+ return new CleanCSS().minify('@import url(test/fixtures/partials/one.css);@import url(http://jakubpawlowicz.com/styles.css);');
+ },
+ 'has right output': function (minified) {
+ assert.equal(minified.styles, '.one{color:red}');
+ },
+ 'has no errors': function (minified) {
+ assert.isEmpty(minified.errors);
+ },
+ 'has a warning': function (minified) {
+ assert.deepEqual(minified.warnings, ['Ignoring remote @import of "http://jakubpawlowicz.com/styles.css" as no callback given.']);
+ }
+ },
+ 'after remote import': {
+ 'topic': function () {
+ return new CleanCSS().minify('@import url(http://jakubpawlowicz.com/reset.css);@import url(http://jakubpawlowicz.com/styles.css);');
+ },
+ 'has right output': function (minified) {
+ assert.equal(minified.styles, '@import url(http://jakubpawlowicz.com/reset.css);@import url(http://jakubpawlowicz.com/styles.css);');
+ },
+ 'has no errors': function (minified) {
+ assert.isEmpty(minified.errors);
+ },
+ 'has a warning': function (minified) {
+ assert.deepEqual(minified.warnings, []);
+ }
+ }
+ },
'buffer passed in': {
'topic': function() {
return new CleanCSS().minify(new Buffer('@import url(test/fixtures/partials/one.css);'));
},
'of a remote resource mixed with local ones but no callback': {
topic: function() {
- var source = '@import url(http://127.0.0.1/remote.css);@import url(test/fixtures/partials/one.css);';
+ var source = '@import url(test/fixtures/partials/one.css);@import url(http://127.0.0.1/remote.css);';
this.reqMocks = nock('http://127.0.0.1')
.get('/remote.css')
.reply(200, 'div{padding:0}');
assert.match(minified.warnings[0], /no callback given/);
},
'should process @import': function (error, minified) {
- assert.equal(minified.styles, '@import url(http://127.0.0.1/remote.css);.one{color:red}');
+ assert.equal(minified.styles, '.one{color:red}');
},
teardown: function() {
assert.isFalse(this.reqMocks.isDone());