You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

136 lines
3.8 KiB

/* eslint-env node */
const glob = require('glob');
const util = require('./util');
const argv = require('minimist')(process.argv.slice(2));
argv._.forEach(arg => {
const tokens = arg.split('=');
argv[tokens[0]] = tokens[1] || true;
});
const currentScopeRegex = /\/\* scoped: ([^*]*) \*\//;
const currentScopeLegacyRegex = new RegExp('\\.(uk-scope)');
const allFiles = [];
if (argv.h || argv.help) {
console.log(`
usage:
scope.js [-s{cope}=your_great_new_scope_name][cleanup]
example:
scope.js // will scope with uk-scope
scope.js -s "my-scope" // will replace any existing scope with my-scope
scope.js cleanup // will remove current scope
`);
} else {
readAllFiles().then(startProcess);
}
function startProcess() {
const currentScope = getCurrentScope();
if (argv.cleanup && currentScope) {
cleanUp(currentScope).then(store).catch(console.log);
} else if (currentScope) {
getNewScope().then(newScope => {
if (currentScope !== newScope) {
cleanUp(currentScope).then(() => doScope(newScope)).then(store).catch(console.log);
} else {
console.log('already scoped with:' + currentScope);
}
});
} else {
getNewScope().then(doScope).then(store).catch(console.log);
}
}
function getNewScope() {
const scopeFromInput = argv.scope || argv.s || 'uk-scope';
if (util.validClassName.test(scopeFromInput)) {
return Promise.resolve(scopeFromInput);
} else {
throw 'illegal scope-name: ' + scopeFromInput;
}
}
function isScoped(data) {
let varName = data.match(currentScopeRegex);
if (varName) {
return varName[1];
} else {
varName = data.match(currentScopeLegacyRegex);
}
return varName && varName[1];
}
function doScope(scopeFromInput) {
const scopes = [];
allFiles.forEach(store => {
scopes.push(util.renderLess(`.${scopeFromInput} {\n${store.data}\n}`)
.then(output =>
store.data = `/* scoped: ${scopeFromInput} */` +
output.replace(new RegExp(`.${scopeFromInput} ${/{(.|[\r\n])*?}/.source}`), '')
.replace(new RegExp(`.${scopeFromInput} ${/\s((\.(uk-(drag|modal-page|offcanvas-page|offcanvas-flip)))|html)/.source}`, 'g'), '$1')
)
);
});
return Promise.all(scopes);
}
function store() {
const writes = [];
allFiles.forEach(({file, data}) => writes.push(util.write(file, data).then(util.minify)));
return Promise.all(writes);
}
function cleanUp(currentScope) {
allFiles.forEach((store) => {
const string = currentScope.split(' ').map(scope => `.${scope}`).join(' ');
store.data = store.data.replace(new RegExp(/ */.source + string + / ({[\s\S]*?})?/.source, 'g'), '') // replace classes
.replace(new RegExp(currentScopeRegex.source, 'g'), ''); // remove scope comment
});
return Promise.resolve();
}
function getCurrentScope() {
let currentScope;
allFiles.forEach(({data}) => {
const scope = isScoped(data);
if (currentScope && scope !== currentScope) {
throw 'scopes used on current css differ from file to file.';
}
currentScope = scope;
});
return currentScope;
}
function readAllFiles() {
return new Promise(res => {
glob('dist/**/!(*.min).css', (err, files) => {
//read files, check scopes
const reads = [];
files.forEach(file => {
const promise = util.read(file, data => {
allFiles.push({file, data});
});
reads.push(promise);
});
Promise.all(reads).then(res);
});
});
}