Skip to content

Instantly share code, notes, and snippets.

@timdp
Created January 7, 2015 13:57
Show Gist options
  • Save timdp/8a84a6115d6a49a04a60 to your computer and use it in GitHub Desktop.
Save timdp/8a84a6115d6a49a04a60 to your computer and use it in GitHub Desktop.
Self-contained Web Font CSS parser
var parseFontCss = (function() {
var WEIGHT_MAP = {
lighter: 300,
normal: 400,
bold: 700,
bolder: 800
};
var getFontFaceBlocks = function(css) {
var reFontFace = /@font-face\s*\{([^}]*)\}/g;
var results = [];
var match;
while ((match = reFontFace.exec(css)) !== null) {
results.push(match[1]);
}
return results;
};
var getCssDeclarations = function(css) {
var reNameValue = /\b([a-z\-]+)\s*:\s*([^;]+)(?:\s*;)?/g;
var results = [];
var match;
while ((match = reNameValue.exec(css)) !== null) {
results.push({
name: match[1],
value: match[2]
});
}
return results;
};
var getFilenameFromUrl = function(meta) {
var pos = meta.url.lastIndexOf('/');
if (pos >= 0) {
meta.path = meta.url.substr(0, pos);
meta.name = meta.url.substr(pos + 1);
} else {
meta.path = '';
meta.name = meta.url;
}
meta.name = meta.name.replace(/[?#].*/, '');
pos = meta.name.lastIndexOf('.');
if (pos >= 0) {
meta.basename = meta.name.substr(0, pos);
meta.ext = meta.name.substr(pos);
} else {
meta.basename = meta.name;
meta.ext = '';
}
};
var parseFontSrc = function(src) {
var reSrc = /\s*(,?)\s*([a-z]+)\((["']?)([^)]+)\3\)/g;
var results = [];
var maybeAdd = function(meta) {
if (!meta.hasOwnProperty('format') || !meta.hasOwnProperty('url')) {
return;
}
getFilenameFromUrl(meta);
results.push(meta);
};
var current = {};
var match;
while ((match = reSrc.exec(src)) !== null) {
var comma = match[1],
key = match[2],
value = match[4];
if (comma) {
maybeAdd(current);
current = {};
}
current[key] = value;
}
maybeAdd(current);
return results;
};
var getNumericFontWeight = function(weightStr) {
if (/^[0-9]+$/.test(weightStr)) {
return parseInt(weightStr, 10);
}
weightStr = unquote(weightStr);
if (WEIGHT_MAP.hasOwnProperty(weightStr)) {
return WEIGHT_MAP[weightStr];
}
return -1;
};
var unquote = function(str) {
return str.replace(/^\s*(["']?)([\s\S]*)\1\s*$/, '$2');
};
var stripComments = function(css) {
return css.replace(/\/\*[\s\S]*?\*\//g, '');
};
return function(css) {
css = stripComments(css);
var blocks = getFontFaceBlocks(css);
var result = {};
for (var i = 0; i < blocks.length; ++i) {
var decl = getCssDeclarations(blocks[i]);
var family = null,
meta = {
weight: 400,
style: 'normal',
files: null
};
var value;
for (var j = 0; j < decl.length; ++j) {
if (decl[j].name === 'font-family') {
value = unquote(decl[j].value);
if (value.length) {
family = value;
}
} else if (decl[j].name === 'font-weight') {
var weight = getNumericFontWeight(decl[j].value);
if (weight > 0) {
meta.weight = weight;
}
} else if (decl[j].name === 'font-style') {
value = unquote(decl[j].value);
meta.style = (value === 'italic') ? 'italic' : 'normal';
} else if (decl[j].name === 'src') {
var files = parseFontSrc(decl[j].value);
if (files.length) {
meta.files = files;
}
}
}
if (family !== null && meta.files !== null) {
if (!result.hasOwnProperty(family)) {
result[family] = [];
}
result[family].push(meta);
}
}
return result;
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment