UNPKG

node-less

Version:

Less Compiler For Node

456 lines (440 loc) 18.2 kB
(function (module) { var Anonymous = require('./anonymous.js'), Color = require('./color.js'), Keyword = require('./keyword.js'), Dimension = require('./dimension.js'), JavaScript = require('./javascript.js'), Quoted = require('./quoted'), URL = require('./url.js'); var functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return scaled(c, 256); }); a = number(a); return new Color(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = clamp(number(s)); l = clamp(number(l)); a = clamp(number(a)); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hsv: function(h, s, v) { return this.hsva(h, s, v, 1.0); }, hsva: function(h, s, v, a) { h = ((number(h) % 360) / 360) * 360; s = number(s); v = number(v); a = number(a); var i, f; i = Math.floor((h / 60) % 6); f = (h / 60) - i; var vs = [v, v * (1 - s), v * (1 - f * s), v * (1 - (1 - f) * s)]; var perm = [[0, 3, 1], [2, 0, 1], [1, 0, 3], [1, 2, 0], [3, 1, 0], [0, 1, 2]]; return this.rgba(vs[perm[i][0]] * 255, vs[perm[i][1]] * 255, vs[perm[i][2]] * 255, a); }, hue: function (color) { return new Dimension(Math.round(color.toHSL().h)); }, saturation: function (color) { return new Dimension(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new Dimension(Math.round(color.toHSL().l * 100), '%'); }, hsvhue: function(color) { return new Dimension(Math.round(color.toHSV().h)); }, hsvsaturation: function (color) { return new Dimension(Math.round(color.toHSV().s * 100), '%'); }, hsvvalue: function (color) { return new Dimension(Math.round(color.toHSV().v * 100), '%'); }, red: function (color) { return new Dimension(color.rgb[0]); }, green: function (color) { return new Dimension(color.rgb[1]); }, blue: function (color) { return new Dimension(color.rgb[2]); }, alpha: function (color) { return new Dimension(color.toHSL().a); }, luma: function (color) { return new Dimension(Math.round(color.luma() * color.alpha * 100), '%'); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fade: function (color, amount) { var hsl = color.toHSL(); hsl.a = amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, mix: function (color1, color2, weight) { if (!weight) { weight = new Dimension(50); } var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new Color(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new Dimension(100)); }, contrast: function (color, dark, light, threshold) { if (!color.rgb) { return null; } if (typeof light === 'undefined') { light = this.rgba(255, 255, 255, 1.0); } if (typeof dark === 'undefined') { dark = this.rgba(0, 0, 0, 1.0); } if (dark.luma() > light.luma()) { var t = light; light = dark; dark = t; } if (typeof threshold === 'undefined') { threshold = 0.43; } else { threshold = number(threshold); } if ((color.luma() * color.alpha) < threshold) { return light; } else { return dark; } }, e: function (str) { return new Anonymous(str instanceof JavaScript ? str.evaluated : str); }, escape: function (str) { return new Anonymous(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new Quoted('"' + str + '"', str); }, unit: function (val, unit) { return new Dimension(val.value, unit ? unit.toCSS() : ""); }, convert: function (val, unit) { return val.convertTo(unit.value); }, round: function (n, f) { var fraction = typeof(f) === "undefined" ? 0 : f.value; return this._math(function(num) { return num.toFixed(fraction); }, null, n); }, pi: function () { return new Dimension(Math.PI); }, mod: function(a, b) { return new Dimension(a.value % b.value, a.unit); }, pow: function(x, y) { if (typeof x === "number" && typeof y === "number") { x = new Dimension(x); y = new Dimension(y); } else if (!(x instanceof Dimension) || !(y instanceof Dimension)) { throw { type: "Argument", message: "arguments must be numbers" }; } return new Dimension(Math.pow(x.value, y.value), x.unit); }, _math: function (fn, unit, n) { if (n instanceof Dimension) { return new Dimension(fn(parseFloat(n.value)), unit == null ? n.unit : unit); } else if (typeof(n) === 'number') { return fn(n); } else { throw { type: "Argument", message: "argument must be a number" }; } }, argb: function (color) { return new Anonymous(color.toARGB()); }, percentage: function (n) { return new Dimension(n.value * 100, '%'); }, color: function (n) { if (n instanceof Quoted) { return new Color(n.value.slice(1)); } else { throw { type: "Argument", message: "argument must be a string" }; } }, iscolor: function (n) { return this._isa(n, Color); }, isnumber: function (n) { return this._isa(n, Dimension); }, isstring: function (n) { return this._isa(n, Quoted); }, iskeyword: function (n) { return this._isa(n, Keyword); }, isurl: function (n) { return this._isa(n, URL); }, ispixel: function (n) { return this.isunit(n, 'px'); }, ispercentage: function (n) { return this.isunit(n, '%'); }, isem: function (n) { return this.isunit(n, 'em'); }, isunit: function (n, unit) { return (n instanceof Dimension) && n.unit.is(unit.value || unit) ? Keyword('true') : Keyword('false'); }, _isa: function (n, Type) { return (n instanceof Type) ? Keyword('true') : Keyword('false'); }, multiply: function(color1, color2) { var r = color1.rgb[0] * color2.rgb[0] / 255; var g = color1.rgb[1] * color2.rgb[1] / 255; var b = color1.rgb[2] * color2.rgb[2] / 255; return this.rgb(r, g, b); }, screen: function(color1, color2) { var r = 255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = 255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = 255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, overlay: function(color1, color2) { var r = color1.rgb[0] < 128 ? 2 * color1.rgb[0] * color2.rgb[0] / 255 : 255 - 2 * (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = color1.rgb[1] < 128 ? 2 * color1.rgb[1] * color2.rgb[1] / 255 : 255 - 2 * (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = color1.rgb[2] < 128 ? 2 * color1.rgb[2] * color2.rgb[2] / 255 : 255 - 2 * (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, softlight: function(color1, color2) { var t = color2.rgb[0] * color1.rgb[0] / 255; var r = t + color1.rgb[0] * (255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255 - t) / 255; t = color2.rgb[1] * color1.rgb[1] / 255; var g = t + color1.rgb[1] * (255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255 - t) / 255; t = color2.rgb[2] * color1.rgb[2] / 255; var b = t + color1.rgb[2] * (255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255 - t) / 255; return this.rgb(r, g, b); }, hardlight: function(color1, color2) { var r = color2.rgb[0] < 128 ? 2 * color2.rgb[0] * color1.rgb[0] / 255 : 255 - 2 * (255 - color2.rgb[0]) * (255 - color1.rgb[0]) / 255; var g = color2.rgb[1] < 128 ? 2 * color2.rgb[1] * color1.rgb[1] / 255 : 255 - 2 * (255 - color2.rgb[1]) * (255 - color1.rgb[1]) / 255; var b = color2.rgb[2] < 128 ? 2 * color2.rgb[2] * color1.rgb[2] / 255 : 255 - 2 * (255 - color2.rgb[2]) * (255 - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, difference: function(color1, color2) { var r = Math.abs(color1.rgb[0] - color2.rgb[0]); var g = Math.abs(color1.rgb[1] - color2.rgb[1]); var b = Math.abs(color1.rgb[2] - color2.rgb[2]); return this.rgb(r, g, b); }, exclusion: function(color1, color2) { var r = color1.rgb[0] + color2.rgb[0] * (255 - color1.rgb[0] - color1.rgb[0]) / 255; var g = color1.rgb[1] + color2.rgb[1] * (255 - color1.rgb[1] - color1.rgb[1]) / 255; var b = color1.rgb[2] + color2.rgb[2] * (255 - color1.rgb[2] - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, average: function(color1, color2) { var r = (color1.rgb[0] + color2.rgb[0]) / 2; var g = (color1.rgb[1] + color2.rgb[1]) / 2; var b = (color1.rgb[2] + color2.rgb[2]) / 2; return this.rgb(r, g, b); }, negation: function(color1, color2) { var r = 255 - Math.abs(255 - color2.rgb[0] - color1.rgb[0]); var g = 255 - Math.abs(255 - color2.rgb[1] - color1.rgb[1]); var b = 255 - Math.abs(255 - color2.rgb[2] - color1.rgb[2]); return this.rgb(r, g, b); }, tint: function(color, amount) { return this.mix(this.rgb(255,255,255), color, amount); }, shade: function(color, amount) { return this.mix(this.rgb(0, 0, 0), color, amount); }, extract: function(values, index) { index = index.value - 1; // (1-based index) return values.value[index]; }, "data-uri": function(mimetypeNode, filePathNode) { if (typeof window !== 'undefined') { return new URL(filePathNode || mimetypeNode, this.currentFileInfo).eval(this.env); } var mimetype = mimetypeNode.value; var filePath = (filePathNode && filePathNode.value); var fs = require("fs"), path = require("path"), useBase64 = false; if (arguments.length < 2) { filePath = mimetype; } if (this.env.isPathRelative(filePath)) { if (this.currentFileInfo.relativeUrls) { filePath = path.join(this.currentFileInfo.currentDirectory, filePath); } else { filePath = path.join(this.currentFileInfo.entryPath, filePath); } } if (arguments.length < 2) { var mime; try { mime = require('mime'); } catch (ex) { mime = require('./mine.js'); } mimetype = mime.lookup(filePath); var charset = mime.charsets.lookup(mimetype); useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0; if (useBase64) mimetype += ';base64'; } else { useBase64 = /;base64$/.test(mimetype) } var buf = fs.readFileSync(filePath); var DATA_URI_MAX_KB = 32, fileSizeInKB = parseInt((buf.length / 1024), 10); if (fileSizeInKB >= DATA_URI_MAX_KB) { if (this.env.ieCompat !== false) { if (!this.env.silent) { console.warn("Skipped data-uri embedding of %s because its size (%dKB) exceeds IE8-safe %dKB!", filePath, fileSizeInKB, DATA_URI_MAX_KB); } return new URL(filePathNode || mimetypeNode, this.currentFileInfo).eval(this.env); } else if (!this.env.silent) { console.warn("WARNING: Embedding %s (%dKB) exceeds IE8's data-uri size limit of %dKB!", filePath, fileSizeInKB, DATA_URI_MAX_KB); } } buf = useBase64 ? buf.toString('base64') : encodeURIComponent(buf); var uri = "'data:" + mimetype + ',' + buf + "'"; return new URL(new Anonymous(uri)); } }; var mathFunctions = [{name:"ceil"}, {name:"floor"}, {name: "sqrt"}, {name:"abs"}, {name:"tan", unit: ""}, {name:"sin", unit: ""}, {name:"cos", unit: ""}, {name:"atan", unit: "rad"}, {name:"asin", unit: "rad"}, {name:"acos", unit: "rad"}]; var createMathFunction = function(name, unit) { return function(n) { if (unit != null) { n = n.unify(); } return this._math(Math[name], unit, n); }; }; for(var i = 0; i < mathFunctions.length; i++) { functions[mathFunctions[i].name] = createMathFunction(mathFunctions[i].name, mathFunctions[i].unit); } function hsla(color) { return functions.hsla(color.h, color.s, color.l, color.a); } function scaled(n, size) { if (n instanceof Dimension && n.unit.is('%')) { return parseFloat(n.value * size / 100); } else { return number(n); } } function number(n) { if (n instanceof Dimension) { return parseFloat(n.unit.is('%') ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } module.exports = functions; })(module);