lithium-sdk
Version:
### Lithium Developer Community Area
431 lines (382 loc) • 13.4 kB
JavaScript
/**
* Skin Object
*
* @author Doug Schroeder
*/
'use strict';
var fs = require('fs');
var path = require('path');
var putils = require('./plugin-utils');
module.exports = function (gulp, gutil) {
var server, localSkins, localResponsiveSkins, otherCommunitySkins;
var skinPropertyCopySass = 'copy_sass_files_to_child';
var baseFeaturePath = gutil.env.newStructure ? 'plugin/res/feature/responsivebase/' : 'res/feature/responsivebase/';
var peakFeaturePath = gutil.env.newStructure ? 'plugin/res/feature/responsivepeak/' : 'res/feature/responsivepeak/';
var themeFeaturePath = 'other/res/skins'
var skinsBaseDir = 'res/skins';
var communityPluginsDir = 'other';
var propFileName = 'skin.properties';
var checkTheme, version;
var themesMap;
var serverVersionThemeCheck = require('../lib/server-version-theme-check.json');
var versionPattern = /(\d+)\.(\d{0,2})*/i;
function isEmpty(obj) {
return Object.keys(obj).length === 0;
}
function checkString(valName, val) {
if (!(typeof val === 'string' || val instanceof String)) {
process.exitCode = 9;
throw Error(valName + ' must be a string!');
}
}
function createSkin(skinId, skinDir) {
return new Skin(skinId, skinDir);
}
var coreResponsiveSkinIds = ['responsive_peak', 'responsive_base'];
//Subset of legacy core skins -- This list is fetched from studio's subset of skins exposed from skin editor.
var coreSkinIds = ['base', 'whiteui', 'proui', 'pacificaui', 'newsui', 'naturalbridgesui', 'mondrian', 'lightui',
'castlerockui', 'anonuevoui' ];
function getCoreResponsiveSkinIds() {
return coreResponsiveSkinIds;
}
/**
* List of all core skins that are not responsive
*/
function getCoreSkinIds() {
return coreSkinIds;
}
/**
* All SDK skins that are not responsive
*/
function getLocalSkins() {
return localSkins ? localSkins : localSkins = fs.readdirSync(skinsBaseDir).filter(function(file) {
var skinDir = path.resolve(skinsBaseDir, file);
return fs.statSync(skinDir).isDirectory();
}).map(function(skinId) {
var skinDir = path.resolve(skinsBaseDir, skinId);
return createSkin(path.basename(skinDir), skinDir);
}).filter(function(skin) {
return !skin.isResponsive() && !skin.getIsTheme();
});
}
/**
* All SDK local skins that are responsive
*/
function getLocalResponsiveSkins() {
return localResponsiveSkins ? localResponsiveSkins
: localResponsiveSkins = fs.readdirSync(skinsBaseDir).filter(function(file) {
var skinDir = path.resolve(skinsBaseDir, file);
return fs.statSync(skinDir).isDirectory();
}).map(function(skinId) {
var skinDir = path.resolve(skinsBaseDir, skinId);
return createSkin(path.basename(skinDir), skinDir);
}).filter(function(skin) {
return skin.isResponsive();
});
}
/**
* Looks recursively under core plugins to fetch feature version for given feature. If not found, returns default
*/
function getResponsiveFeatureVersionFromCore(featurePath, defaultPath) {
var server = getServer();
var coreFeaturePath = path.resolve(server.coreOutputDir(), featurePath);
if (!fs.existsSync(coreFeaturePath)) {
putils.logWarning(gutil, 'No directory found under coreplugins for '+ featurePath + '. Returning default: ' + defaultPath);
return defaultPath;
}
var featureVersion = fs.readdirSync(coreFeaturePath).filter(function(dir) {
return path.basename(dir).match(/v\S+-lia\S+/);
}).map(function(dir) {
return path.basename(dir);
});
if (featureVersion === undefined || featureVersion.length === 0) {
putils.logWarning(gutil, 'No feature version found under coreplugins for '+featurePath + '. Returning default');
return defaultPath;
}
return featureVersion[0];
}
/**
* This function returns skins from other plugins in community. This is found in coreplugins directory under other.
*/
function getOtherCommunitySkins() {
if (otherCommunitySkins) {
return otherCommunitySkins;
}
var skinBasePath = path.resolve(getServer().coreOutputDir(), communityPluginsDir, skinsBaseDir);
if (!fs.existsSync(skinBasePath)) {
//No other community plugins found
return [];
}
otherCommunitySkins = fs.readdirSync(skinBasePath).filter(function(file) {
var skinDir = path.resolve(skinBasePath, file);
return fs.statSync(skinDir).isDirectory();
}).map(function(skinId) {
var skinDir = path.resolve(skinBasePath, skinId);
return createSkin(path.basename(skinDir), skinDir);
});
return otherCommunitySkins;
}
function isFile(path) {
try {
return fs.statSync(path).isFile();
} catch (err) {
return false;
}
}
function isDirectory(path) {
try {
return fs.statSync(path).isDirectory();
} catch (err) {
return false;
}
}
function getServer() {
return server ? server : server = require('./server.js')(gulp, gutil);
}
/**
* This function looks up a skinId on the file system, including skinIds that are core and responsive.
*/
function findBaseDirForSkin(skinId) {
//Is the skin local skin?
var localSkinIds = fs.readdirSync(skinsBaseDir).filter(function(file) {
var skinDir = path.resolve(skinsBaseDir, file);
return fs.statSync(skinDir).isDirectory();
});
if (localSkinIds.indexOf(skinId) > -1) {
return path.resolve(skinsBaseDir, skinId);
}
//Fetch base directories for core responsive skins
var server = getServer();
if (getCoreResponsiveSkinIds().indexOf(skinId) > -1) {
if (skinId.indexOf('responsive_peak') > -1) {
return path.resolve(server.coreOutputDir(), peakFeaturePath,
getResponsiveFeatureVersionFromCore(peakFeaturePath, server.localSkinCompileVersion()),
skinsBaseDir, skinId);
} else if (skinId.indexOf('responsive_base') > -1) {
return path.resolve(server.coreOutputDir(), baseFeaturePath,
getResponsiveFeatureVersionFromCore(baseFeaturePath, server.localSkinCompileVersion()),
skinsBaseDir, 'bootstrap_base');
} else {
process.exitCode = 1;
throw new Error('Invalid parent core responsive skin=' + skinId);
}
}
//Fetch base directories for core legacy skins
if (getCoreSkinIds().indexOf(skinId) > -1) {
return path.resolve(server.coreOutputDir(), skinsBaseDir, skinId);
}
//Check if this is a community skin from other plugins
var likelyPath = path.resolve(server.coreOutputDir(), communityPluginsDir, skinsBaseDir, skinId);
if (fs.statSync(likelyPath).isDirectory()) {
return likelyPath;
}
//Should we error here? or just create a skin with unknown skinId
process.exitCode = 1;
throw new Error('Invalid skin=' + skinId);
}
function Skin(id, dir) {
checkString('id', id);
checkString('dir', dir);
var skinProperties = {};
var parent = null;
var attribs = {};
var isTheme = false;
var getAttrib = function(key, fPopulator) {
if (attribs[key] === undefined) {
attribs[key] = fPopulator(key);
}
return attribs[key];
};
function addSkinProp(line) {
var key;
var val;
var lineItem;
// Look up skin property values in file
if (line.indexOf('+=') > -1 ) {
// Property is an array
lineItem = line.split('+=');
if (lineItem.length !== 2) {
return;
}
// Allow multi values to be property arrays
key = lineItem[0].trim();
val = lineItem[1].trim();
if (key in skinProperties) {
var origVal = skinProperties[key];
if (!(origVal instanceof Array)) {
skinProperties[key] = [];
skinProperties[key].push(origVal);
}
} else {
skinProperties[key] = [];
}
skinProperties[key].push(val);
} else {
//Property is a simple string
lineItem = line.split('=');
if (lineItem.length !== 2) {
return;
}
key = lineItem[0].trim();
val = lineItem[1].trim();
skinProperties[key] = val;
}
}
function getSkinProperties(skin) {
if (isEmpty(skinProperties)) {
if (skin.isLocal()) {
var filePath = path.resolve(skin.getDir(), propFileName);
if (isFile(filePath)) {
var fileVal = fs.readFileSync(filePath).toString();
var fileValByLines = fileVal.split('\n');
if (fileValByLines.length > 0) {
fileValByLines.forEach(function (line) {
addSkinProp(line);
});
} else {
// FIXME: line is not set at this point
addSkinProp(line);
}
}
} else {
// TODO: add skins api call to get skin properties
}
if (isEmpty(skinProperties)) {
skinProperties.empty = true;
}
}
return skinProperties;
}
this.getIsTheme = function() {
return isTheme;
}
this.setIsTheme = function(isThemeSkin) {
isTheme = isThemeSkin;
}
this.getId = function() {
return id;
};
this.getDir = function () {
return dir;
};
this.lookupProperty = function (key) {
return getSkinProperties(this)[key];
};
this.getParentId = function () {
return this.lookupProperty('parent');
};
this.getParent = function () {
if (!parent) {
var parentId = this.getParentId();
if (parentId) {
if (parentId.includes("theme")) {
var matches = version.toString().match(versionPattern);
var versionOnServer = parseInt(matches[1]);
var minorVersionOnServer = parseInt(matches[2]);
if (versionOnServer < serverVersionThemeCheck.supportedVersionMajor ||
(versionOnServer == serverVersionThemeCheck.supportedVersionMajor &&
minorVersionOnServer < serverVersionThemeCheck.supportedVersionMinor)) {
isTheme = true;
return null;
}
var isEnabled = themesMap.get(parentId);
if(isEnabled === 'true') {
parent = new Skin(parentId, findBaseDirForSkin(parentId));
} else {
isTheme = true;
parent = null;
}
} else {
parent = new Skin(parentId, findBaseDirForSkin(parentId));
}
}
}
return parent;
};
this.getResponsiveCoreId = function() {
var responsiveBaseSkins = getCoreResponsiveSkinIds();
if (responsiveBaseSkins.indexOf(this.getId()) > -1) {
return this.getId();
}
var parent = this.getParent();
if (parent) {
if (responsiveBaseSkins.indexOf(parent.getId()) > -1) {
return parent.getId();
} else {
return parent.getResponsiveCoreId();
}
}
return null;
};
this.isLocal = function () {
var skin = this;
return getAttrib('local', function () {
return isDirectory(skin.getDir());
});
};
this.isResponsive = function () {
var skin = this;
return getAttrib('responsive', function () {
var skinId = skin.getId();
var responsiveSkin = getCoreResponsiveSkinIds().indexOf(skinId) > -1;
if (!responsiveSkin) {
var parent = skin.getParent();
if (parent != null) {
responsiveSkin = parent.isResponsive();
skin.setIsTheme(parent.getIsTheme());
}
}
return responsiveSkin;
});
};
}
var responsiveSkins = [];
var responsiveSkinByIdMap = {};
function setLiaVersion(liaVersion) {
version = liaVersion;
}
function setThemesMap(themesEnabledMap) {
themesMap = themesEnabledMap;
}
return {
Skin: Skin,
getResponsiveSkins: function() {
if (isEmpty(responsiveSkins)) {
responsiveSkins.push.apply(responsiveSkins, getLocalResponsiveSkins());
responsiveSkins.forEach(function(skin) {
responsiveSkinByIdMap[skin.getId()] = skin;
});
}
return responsiveSkins;
},
getResponsiveSkinIds: function() {
return this.getResponsiveSkins().filter(function() {
return true;
}).map(function(skin) {
return skin.getId();
});
},
lookupResponsiveSkin: function(skinId) {
// in case it's not cached yet
this.getResponsiveSkinIds();
return responsiveSkinByIdMap[skinId];
},
getCoreSkinIds: getCoreSkinIds,
getCoreResponsiveSkinIds: getCoreResponsiveSkinIds,
getLocalSkins: getLocalSkins,
getOtherCommunitySkins: getOtherCommunitySkins,
peakFeaturePath : peakFeaturePath,
baseFeaturePath: baseFeaturePath,
skinPropertyCopySass: skinPropertyCopySass,
skinsBaseDir : skinsBaseDir,
themeFeaturePath: themeFeaturePath,
findBaseDirForSkin: findBaseDirForSkin,
setLiaVersion: setLiaVersion,
setThemesMap: setThemesMap,
sassDir : 'sass',
componentsDir : 'components',
skinSubFolder : ['desktop', 'mobile'],
skinPropertiesFileName: propFileName,
cssDir: 'css'
};
};