Skip to content

Commit

Permalink
Merge pull request #16 from marikaner/scope_option
Browse files Browse the repository at this point in the history
Scope option
  • Loading branch information
matz3 authored Dec 13, 2017
2 parents 02dca50 + 0cde0d9 commit af674a8
Show file tree
Hide file tree
Showing 3 changed files with 559 additions and 100 deletions.
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,28 @@ Type `string`
Dot-separated name of the corresponding library.
It will be used to inline the `variables` JSON as data-uri which can be retrieved at runtime.

##### scope

Type `object`

Scope options to be set when not using a .theming file. The available settings are:
* `selector`
* `embeddedFilePath`
* `embeddedCompareFilePath`
* `baseFilePath`

Those settings correspond to the aScopes property of the .theming file. When using this options all four settings have to be set.

Example:
```js
scope: {
selector: "scopeSelector",
embeddedFilePath: "src/themes/theme_to_be_embedded.less",
embeddedCompareFilePath: "src/themes/basetheme_to_compare_embedded_theme_to.less",
baseFilePath: "src/themes/basetheme_to_compare_embedded_theme_to.less"
}
```

#### result

##### css
Expand Down
216 changes: 117 additions & 99 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ Builder.prototype.build = function(options) {
rootPaths: [],
parser: {},
compiler: {},
library: {}
library: {},
scope: {}
}, options);

// Set default of "relativeUrls" parser option to "true" (less default is "false")
Expand Down Expand Up @@ -264,6 +265,104 @@ Builder.prototype.build = function(options) {
});
}

function compileWithScope(scopeOptions) {
// 1. Compile base + embedded files (both default + RTL variants)
return Promise.all([
fileUtils.readFile(scopeOptions.embeddedCompareFilePath, options.rootPaths).then(compile),
fileUtils.readFile(scopeOptions.embeddedFilePath, options.rootPaths).then(compile)
]).then(function(results) {
return {
embeddedCompare: results[0],
embedded: results[1]
};
}).then(function(results) {
var sScopeName = scopeOptions.selector;

function applyScope(embeddedCompareCss, embeddedCss, bRtl) {

var restoreStringPrototype = cleanupStringPrototype();

// Create diff object between embeddedCompare and embedded
var oBase = css.parse(embeddedCompareCss);
var oEmbedded = css.parse(embeddedCss);

restoreStringPrototype();

var oDiff = diff(oBase, oEmbedded);

// Create scope
var sScopeSelector = '.' + sScopeName;
var oScope = scope(oDiff.diff, sScopeSelector);

var oCssScopeRoot;

if (oDiff.stack) {
oCssScopeRoot = scope.scopeCssRoot(oDiff.stack.stylesheet.rules, sScopeName);

if (oCssScopeRoot) {
oScope.stylesheet.rules.unshift(oCssScopeRoot);
}
}

// Append scope + stack to embeddedCompareFile (actually target file, which is currently always the same i.e. "library.css")
// The stack gets appended to the embeddedFile only
var sAppend = css.stringify(oScope);

if (scopeOptions.baseFilePath !== options.lessInputPath && oDiff.stack && oDiff.stack.stylesheet.rules.length > 0) {
sAppend += "\n" + css.stringify(oDiff.stack);
}

return sAppend + "\n";

}

results.embeddedCompare.css += applyScope(results.embeddedCompare.css, results.embedded.css);
if (options.rtl) {
results.embeddedCompare.cssRtl += applyScope(results.embeddedCompare.cssRtl, results.embedded.cssRtl, true);
}

// Create diff between embeddedCompare and embeded variables
var oVariablesBase = results.embeddedCompare.variables;
var oVariablesEmbedded = results.embedded.variables;
var oVariablesDiff = {};

for (var sKey in oVariablesEmbedded) {
if (sKey in oVariablesBase) {
if (oVariablesBase[sKey] != oVariablesEmbedded[sKey]) {
oVariablesDiff[sKey] = oVariablesEmbedded[sKey];
}
}
}

// Merge variables
var oVariables = {};
oVariables["default"] = oVariablesBase;
oVariables["scopes"] = {};
oVariables["scopes"][sScopeName] = oVariablesDiff;

results.embeddedCompare.variables = oVariables;

var concatImports = function(aImportsBase, aImportsEmbedded) {
var aConcats = aImportsBase.concat(aImportsEmbedded);

return aConcats.filter(function(sImport, sIndex) {
return aConcats.indexOf(sImport) == sIndex;
})
};

if (scopeOptions.baseFilePath !== options.lessInputPath) {
results.embeddedCompare.imports = concatImports(results.embedded.imports, results.embeddedCompare.imports);
} else {
results.embeddedCompare.imports = concatImports(results.embeddedCompare.imports, results.embedded.imports);
}

// 6. Resolve promise with complete result object (css, cssRtl, variables, imports)
return results.embeddedCompare;

});
}


function readDotTheming(dotThemingInputPath) {
return fileUtils.readFile(dotThemingInputPath, options.rootPaths).then(function(result) {

Expand Down Expand Up @@ -296,108 +395,19 @@ Builder.prototype.build = function(options) {
"\"sEmbeddedCompareFile\" (\"" + oScopeConfig.sEmbeddedCompareFile + "\")");
}

var baseFilePath = path.posix.join(themeDir, sBaseFile) + '.source.less';
var embeddedCompareFilePath = path.posix.join(themeDir, sEmbeddedCompareFile) + '.source.less';
var embeddedFilePath = path.posix.join(themeDir, sEmbeddedFile) + '.source.less';

// 1. Compile base + embedded files (both default + RTL variants)
return Promise.all([
fileUtils.readFile(embeddedCompareFilePath, options.rootPaths).then(compile),
fileUtils.readFile(embeddedFilePath, options.rootPaths).then(compile)
]).then(function(results) {
return {
embeddedCompare: results[0],
embedded: results[1]
};
}).then(function(results) {

// baseFile or embeddedFile
var sLibraryBaseFile = dotTheming.mCssScopes.library.sBaseFile;
var sScopeName = oScopeConfig.sSelector;

function applyScope(embeddedCompareCss, embeddedCss, bRtl) {

var restoreStringPrototype = cleanupStringPrototype();

// Create diff object between embeddedCompare and embedded
var oBase = css.parse(embeddedCompareCss);
var oEmbedded = css.parse(embeddedCss);

restoreStringPrototype();

var oDiff = diff(oBase, oEmbedded);

// Create scope
var sScopeSelector = '.' + sScopeName;
var oScope = scope(oDiff.diff, sScopeSelector);

var oCssScopeRoot;

if (oDiff.stack) {
oCssScopeRoot = scope.scopeCssRoot(oDiff.stack.stylesheet.rules, sScopeName);

if (oCssScopeRoot) {
oScope.stylesheet.rules.unshift(oCssScopeRoot);
}
}

// Append scope + stack to embeddedCompareFile (actually target file, which is currently always the same i.e. "library.css")
// The stack gets appended to the embeddedFile only
var sAppend = css.stringify(oScope);

if (sLibraryBaseFile !== "library" && oDiff.stack && oDiff.stack.stylesheet.rules.length > 0) {
sAppend += "\n" + css.stringify(oDiff.stack);
}

return sAppend + "\n";

}

results.embeddedCompare.css += applyScope(results.embeddedCompare.css, results.embedded.css);
if (options.rtl) {
results.embeddedCompare.cssRtl += applyScope(results.embeddedCompare.cssRtl, results.embedded.cssRtl, true);
}

// Create diff between embeddedCompare and embeded variables
var oVariablesBase = results.embeddedCompare.variables;
var oVariablesEmbedded = results.embedded.variables;
var oVariablesDiff = {};

for (var sKey in oVariablesEmbedded) {
if (sKey in oVariablesBase) {
if (oVariablesBase[sKey] != oVariablesEmbedded[sKey]) {
oVariablesDiff[sKey] = oVariablesEmbedded[sKey];
}
}
}

// Merge variables
var oVariables = {};
oVariables["default"] = oVariablesBase;
oVariables["scopes"] = {};
oVariables["scopes"][sScopeName] = oVariablesDiff;

results.embeddedCompare.variables = oVariables;

var concatImports = function(aImportsBase, aImportsEmbedded) {
var aConcats = aImportsBase.concat(aImportsEmbedded);

return aConcats.filter(function(sImport, sIndex) {
return aConcats.indexOf(sImport) == sIndex;
})
};

if (sLibraryBaseFile !== "library") {
results.embeddedCompare.imports = concatImports(results.embedded.imports, results.embeddedCompare.imports);
} else {
results.embeddedCompare.imports = concatImports(results.embeddedCompare.imports, results.embedded.imports);
}

// add .theming file to result.embeddedCompare.imports
results.embeddedCompare.imports.push(dotThemingFilePath);

// 6. Resolve promise with complete result object (css, cssRtl, variables, imports)
return results.embeddedCompare;

return compileWithScope({
selector: oScopeConfig.sSelector,
embeddedFilePath: embeddedFilePath,
embeddedCompareFilePath: embeddedCompareFilePath,
baseFilePath: baseFilePath
}).then(function(embeddedCompare) {
embeddedCompare.imports.push(dotThemingFilePath);
return embeddedCompare;
});
}
}
Expand Down Expand Up @@ -440,14 +450,22 @@ Builder.prototype.build = function(options) {
themeCache = that.getThemeCache(fileInfo.path);
}

var scopeOptions = options.scope;

// Compile theme if not cached or RTL is requested and missing in cache
if (!themeCache || (options.rtl && !themeCache.result.cssRtl)) {
if (scopeOptions.selector && scopeOptions.embeddedFilePath && scopeOptions.embeddedCompareFilePath && scopeOptions.baseFilePath) {
return compileWithScope(scopeOptions).then(addInlineParameters).then(that.cacheTheme.bind(that));
}
return readDotTheming(dotThemingInputPath).then(addInlineParameters).then(that.cacheTheme.bind(that));
} else {
return fileUtils.statFiles(themeCache.result.imports).then(function(newStats) {
for (var i = 0; i < newStats.length; i++) {
// check if .theming and less files have changed since last less compilation
if (!newStats[i] || newStats[i].stat.mtime.getTime() !== themeCache.stats[i].stat.mtime.getTime()) {
if (scopeOptions.selector && scopeOptions.embeddedFilePath && scopeOptions.embeddedCompareFilePath && scopeOptions.baseFilePath) {
return compileWithScope(scopeOptions).then(addInlineParameters).then(that.cacheTheme.bind(that));
}
return readDotTheming(dotThemingInputPath).then(addInlineParameters).then(that.cacheTheme.bind(that));
}
}
Expand Down
Loading

0 comments on commit af674a8

Please sign in to comment.