Skip to content

Mac fonts check #335

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

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions src/rules/check-fonts-alternatives.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*global CSSLint*/
CSSLint.addRule({

//rule information
id: "check-fonts-alternatives",
name: "Check font alternatives",
desc: "Check font alternatives for Mac OS (OS X, iOS)",
browsers: "All",

//initialization
init: function(parser, reporter){
var rule = this,
macMap = {
"Tahoma": "Geneva",
"Lucida Console": "Monaco",
"Lucida Sans Unicode": "Lucida Grande",
"Palatino Linotype": "Palatino",
"Book Antiqua": "Palatino",
"Wingdings": "Zapf Dingbats",
"MS Sans Serif": "Geneva",
"MS Serif": "New York"
},
skipIdentifiers = {
// font-style related
"normal": 1,
"italic": 2,
"oblique": 3,
// any
"inherit": 4,
// font-variant related
"small-caps": 5,
// font-weight related
"bold": 6,
"bolder": 7,
"lighter": 8,
// font-size related
"xx-small": 9,
"x-small": 10,
"small": 11,
"medium": 12,
"large": 13,
"x-large": 14,
"xx-large": 15,
"larger": 16,
"smaller": 17
},
fontFaceRule = false;

// Disable checking inside @font-face block
parser.addListener("startfontface", function(){
fontFaceRule = true;
});

parser.addListener("endfontface", function(){
fontFaceRule = false;
});

parser.addListener("property", function(event){

// font: [font-style||font-variant||font-weight] font-size[/line-height] font-family | inherit
// font-style: normal | italic | oblique | inherit
// font-variant: normal | small-caps | inherit
// font-weight: bold|bolder|lighter|normal|100|200|300|400|500|600|700|800|900
// font-size: absolute | relative | value | precents | inherit
// font-size-absolute: xx-small, x-small, small, medium, large, x-large, xx-large
// font-size-relative: larger | smaller

var property = event.property,
propertyName = property.text.toLowerCase(),
valueParts = event.value.parts,
currentRuleFonts = {},
idStack = [],
i, l, value;

// Skip any detection if we inside @font-face block
if(fontFaceRule) {
return;
}

if(propertyName == "font" || propertyName == "font-family") {
for(i = 0, l = valueParts.length; i < l; i++) {
value = valueParts[i];
if(value.type == 'identifier') {
// skip not-font-family-related identifiers
if(value.text in skipIdentifiers) {
continue;
}
idStack.push(value.text);
} else if(value.type == 'operator' && value.text == ',') {
currentRuleFonts[idStack.join(' ')] = { line: value.line, col: value.col };
idStack = [];
}
}
if(idStack.length > 0) {
currentRuleFonts[idStack.join(' ')] = { line: value.line, col: value.col };
}

for(i in currentRuleFonts) {
if(currentRuleFonts.hasOwnProperty(i)) {
if(i in macMap && currentRuleFonts[macMap[i]] === undefined) {
reporter.warn("No MacOS-alternative for font '" + i + "'. " +
"Consider adding '" + macMap[i] + "'.",
currentRuleFonts[i].line,
currentRuleFonts[i].col,
rule);
}
}
}
}
});

}

});
152 changes: 152 additions & 0 deletions tests/rules/check-fonts-alternatives.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
(function(){

/*global YUITest, CSSLint*/
var
Assert = YUITest.Assert,
testSpec = { "check-fonts-alternatives": 1 };

function mkErrorMessage(font, alternative) {
return "No MacOS-alternative for font '" + font + "'. Consider adding '" + alternative + "'.";
}

YUITest.TestRunner.add(new YUITest.TestCase({

name: "Mac alternative font checker - font property",

"No erros when no Mac alternative needed": function(){
var result = CSSLint.verify(".c { font-family: Arial }", testSpec);

Assert.areEqual(0, result.messages.length);
},

"No erros when Mac alternative is specified": function(){
var result = CSSLint.verify(".c { font: 14px Tahoma, Geneva }", testSpec);

Assert.areEqual(0, result.messages.length);
},

"Font size + family form": function(){
var result = CSSLint.verify(".c { font: 14px Lucida Console }", testSpec);

Assert.areEqual(1, result.messages.length);
Assert.areEqual(mkErrorMessage("Lucida Console", "Monaco"), result.messages[0].message);
},

"Font variant, size, family form": function(){
var result = CSSLint.verify(".c { font: italic 14px MS Serif }", testSpec);

Assert.areEqual(1, result.messages.length);
Assert.areEqual(mkErrorMessage("MS Serif", "New York"), result.messages[0].message);
},

"Font weight, size, family form": function(){
var result = CSSLint.verify(".c { font: bold 14px MS Serif }", testSpec);

Assert.areEqual(1, result.messages.length);
Assert.areEqual(mkErrorMessage("MS Serif", "New York"), result.messages[0].message);
},

"Font weight as number, size + family form": function(){
var result = CSSLint.verify(".c { font: 500 14px MS Serif }", testSpec);

Assert.areEqual(1, result.messages.length);
Assert.areEqual(mkErrorMessage("MS Serif", "New York"), result.messages[0].message);
},

"Font size/height + family form": function(){
var result = CSSLint.verify(".c { font: 14px/20px MS Serif }", testSpec);

Assert.areEqual(1, result.messages.length);
Assert.areEqual(mkErrorMessage("MS Serif", "New York"), result.messages[0].message);
},

"Font size (absolute) + family form": function(){
var result = CSSLint.verify(".c { font: xx-small MS Serif }", testSpec);

Assert.areEqual(1, result.messages.length);
Assert.areEqual(mkErrorMessage("MS Serif", "New York"), result.messages[0].message);
},

"Font size (relative) + family form": function(){
var result = CSSLint.verify(".c { font: larger MS Serif }", testSpec);

Assert.areEqual(1, result.messages.length);
Assert.areEqual(mkErrorMessage("MS Serif", "New York"), result.messages[0].message);
},

"Font - badly formed rule": function(){
// This is equal to identifier 'Tahoma Tahoma Tahoma'
var result = CSSLint.verify(".c { font: 14px Tahoma Tahoma Tahoma }", testSpec);

Assert.areEqual(0, result.messages.length);
},

"Multiple font families without an alternative": function(){
var result = CSSLint.verify(".c { font: 14px MS Serif, Tahoma, Verdana }", testSpec);

Assert.areEqual(2, result.messages.length);
Assert.areEqual(mkErrorMessage("MS Serif", "New York"), result.messages[0].message);
Assert.areEqual(mkErrorMessage("Tahoma", "Geneva"), result.messages[1].message);
},

"Font = inherit": function() {
var result = CSSLint.verify(".c { font: inherit }", testSpec);

Assert.areEqual(0, result.messages.length);
}

}));

YUITest.TestRunner.add(new YUITest.TestCase({

name: "Mac alternative font checker - font-family property",

"No erros when no Mac alternative needed": function(){
var result = CSSLint.verify(".c { font-family: Arial }", testSpec);

Assert.areEqual(0, result.messages.length);
},

"No erros when Mac alternative is specified": function(){
var result = CSSLint.verify(".c { font-family: Tahoma, Geneva }", testSpec);

Assert.areEqual(0, result.messages.length);
},

"No alternative specified, font-family without space": function(){
var result = CSSLint.verify(".c { font-family: Tahoma }", testSpec);

Assert.areEqual(1, result.messages.length);
Assert.areEqual(mkErrorMessage("Tahoma", "Geneva"), result.messages[0].message);
},

"No alternative specified, font-family with space": function(){
var result = CSSLint.verify(".c { font-family: MS Serif }", testSpec);

Assert.areEqual(1, result.messages.length);
Assert.areEqual(mkErrorMessage("MS Serif", "New York"), result.messages[0].message);
},

"No alternative specified, font-family with space, multiple families": function(){
var result = CSSLint.verify(".c { font-family: MS Serif, Tahoma, Arial }", testSpec);

Assert.areEqual(2, result.messages.length);
Assert.areEqual(mkErrorMessage("MS Serif", "New York"), result.messages[0].message);
Assert.areEqual(mkErrorMessage("Tahoma", "Geneva"), result.messages[1].message);
},

"No detection inside @font-face rule 1": function() {
var result = CSSLint.verify("@font-face { font-family: MyFont; }", testSpec);

Assert.areEqual(0, result.messages.length);
},

"No detection inside @font-face rule 2": function() {
var result = CSSLint.verify("@font-face { font-family: Tahoma; }", testSpec);

Assert.areEqual(0, result.messages.length);
}

}));

})();