less
Version:
Leaner CSS
166 lines (139 loc) • 5.6 kB
JavaScript
const contexts = {};
export default contexts;
import * as Constants from './constants.js';
const copyFromOriginal = function copyFromOriginal(original, destination, propertiesToCopy) {
if (!original) { return; }
for (let i = 0; i < propertiesToCopy.length; i++) {
if (Object.prototype.hasOwnProperty.call(original, propertiesToCopy[i])) {
destination[propertiesToCopy[i]] = original[propertiesToCopy[i]];
}
}
};
/*
parse is used whilst parsing
*/
const parseCopyProperties = [
// options
'paths', // option - unmodified - paths to search for imports on
'rewriteUrls', // option - whether to adjust URL's to be relative
'rootpath', // option - rootpath to append to URL's
'strictImports', // option -
'insecure', // option - whether to allow imports from insecure ssl hosts
'dumpLineNumbers', // option - @deprecated The dumpLineNumbers option is deprecated. Use sourcemaps instead. All modes ('comments', 'mediaquery', 'all') will be removed in a future version.
'compress', // option - whether to compress
'syncImport', // option - whether to import synchronously
'mime', // browser only - mime type for sheet import
'useFileCache', // browser only - whether to use the per file session cache
// context
'processImports', // option & context - whether to process imports. if false then imports will not be imported.
// Used by the import manager to stop multiple import visitors being created.
'pluginManager', // Used as the plugin manager for the session
'quiet', // option - whether to log warnings
'quietDeprecations', // option - whether to suppress deprecation warnings only
];
contexts.Parse = function(options) {
copyFromOriginal(options, this, parseCopyProperties);
if (typeof this.paths === 'string') { this.paths = [this.paths]; }
};
const evalCopyProperties = [
'paths', // additional include paths
'compress', // whether to compress
'math', // whether math has to be within parenthesis
'strictUnits', // whether units need to evaluate correctly
'sourceMap', // whether to output a source map
'importMultiple', // whether we are currently importing multiple copies
'urlArgs', // whether to add args into url tokens
'javascriptEnabled', // option - whether Inline JavaScript is enabled. if undefined, defaults to false
'pluginManager', // Used as the plugin manager for the session
'importantScope', // used to bubble up !important statements
'rewriteUrls' // option - whether to adjust URL's to be relative
];
contexts.Eval = function(options, frames) {
copyFromOriginal(options, this, evalCopyProperties);
if (typeof this.paths === 'string') { this.paths = [this.paths]; }
this.frames = frames || [];
this.importantScope = this.importantScope || [];
};
contexts.Eval.prototype.enterCalc = function () {
if (!this.calcStack) {
this.calcStack = [];
}
this.calcStack.push(true);
this.inCalc = true;
};
contexts.Eval.prototype.exitCalc = function () {
this.calcStack.pop();
if (!this.calcStack.length) {
this.inCalc = false;
}
};
contexts.Eval.prototype.inParenthesis = function () {
if (!this.parensStack) {
this.parensStack = [];
}
this.parensStack.push(true);
};
contexts.Eval.prototype.outOfParenthesis = function () {
this.parensStack.pop();
};
contexts.Eval.prototype.inCalc = false;
contexts.Eval.prototype.mathOn = true;
contexts.Eval.prototype.isMathOn = function (op) {
if (!this.mathOn) {
return false;
}
if (op === '/' && this.math !== Constants.Math.ALWAYS && (!this.parensStack || !this.parensStack.length)) {
return false;
}
if (this.math > Constants.Math.PARENS_DIVISION) {
return this.parensStack && this.parensStack.length;
}
return true;
};
contexts.Eval.prototype.pathRequiresRewrite = function (path) {
const isRelative = this.rewriteUrls === Constants.RewriteUrls.LOCAL ? isPathLocalRelative : isPathRelative;
return isRelative(path);
};
contexts.Eval.prototype.rewritePath = function (path, rootpath) {
let newPath;
rootpath = rootpath || '';
newPath = this.normalizePath(rootpath + path);
// If a path was explicit relative and the rootpath was not an absolute path
// we must ensure that the new path is also explicit relative.
if (isPathLocalRelative(path) &&
isPathRelative(rootpath) &&
isPathLocalRelative(newPath) === false) {
newPath = `./${newPath}`;
}
return newPath;
};
contexts.Eval.prototype.normalizePath = function (path) {
const segments = path.split('/').reverse();
let segment;
path = [];
while (segments.length !== 0) {
segment = segments.pop();
switch ( segment ) {
case '.':
break;
case '..':
if ((path.length === 0) || (path[path.length - 1] === '..')) {
path.push( segment );
} else {
path.pop();
}
break;
default:
path.push(segment);
break;
}
}
return path.join('/');
};
function isPathRelative(path) {
return !/^(?:[a-z-]+:|\/|#)/i.test(path);
}
function isPathLocalRelative(path) {
return path.charAt(0) === '.';
}
// todo - do the same for the toCSS ?