blob: 20553651848822be6d8d4143f92b8d1b86abdceb [file] [log] [blame]
/*******************************
Set-up
*******************************/
var
fs = require('fs'),
path = require('path'),
defaults = require('../defaults'),
release = require('./release'),
requireDotFile = require('require-dot-file')
;
/*******************************
When to Ask
*******************************/
/* Preconditions for install questions */
var when = {
// path
changeRoot: function(questions) {
return (questions.useRoot !== undefined && questions.useRoot !== true);
},
// permissions
changePermissions: function(questions) {
return (questions.changePermissions && questions.changePermissions === true);
},
// install
hasConfig: function() {
return requireDotFile('semantic.json', process.cwd());
},
allowOverwrite: function(questions) {
return (questions.overwrite === undefined || questions.overwrite == 'yes');
},
notAuto: function(questions) {
return (questions.install !== 'auto' && (questions.overwrite === undefined || questions.overwrite == 'yes'));
},
custom: function(questions) {
return (questions.install === 'custom' && (questions.overwrite === undefined || questions.overwrite == 'yes'));
},
express: function(questions) {
return (questions.install === 'express' && (questions.overwrite === undefined || questions.overwrite == 'yes'));
},
// customize
customize: function(questions) {
return (questions.customize === true);
},
primaryColor: function(questions) {
return (questions.primaryColor);
},
secondaryColor: function(questions) {
return (questions.secondaryColor);
}
};
/*******************************
Response Filters
*******************************/
/* Filters to user input from install questions */
var filter = {
removeTrailingSlash: function(path) {
return path.replace(/(\/$|\\$)+/mg, '');
}
};
/*******************************
Configuration
*******************************/
module.exports = {
// check whether install is setup
isSetup: function() {
return when.hasConfig();
},
// detect whether there is a semantic.json configuration and that the auto-install option is set to true
shouldAutoInstall: function() {
var
config = when.hasConfig()
;
return config['autoInstall'];
},
// checks if files are in a PM directory
getPackageManager: function(directory) {
var
// returns last matching result (avoid sub-module detection)
walk = function(directory) {
var
pathArray = directory.split(path.sep),
folder = pathArray[pathArray.length - 1],
nextDirectory = path.join(directory, path.sep, '..')
;
if( folder == 'bower_components') {
return {
name: 'Bower',
root: nextDirectory
};
}
else if(folder == 'node_modules') {
return {
name: 'NPM',
root: nextDirectory
};
}
else if(folder == 'composer') {
return {
name: 'Composer',
root: nextDirectory
};
}
if(path.resolve(directory) == path.resolve(nextDirectory)) {
return false;
}
// recurse downward
return walk(nextDirectory);
}
;
// start walk from current directory if none specified
directory = directory || (__dirname + path.sep);
return walk(directory);
},
// checks if files is PMed submodule
isSubModule: function(directory) {
var
moduleFolders = 0,
walk = function(directory) {
var
pathArray = directory.split(path.sep),
folder = pathArray[pathArray.length - 2],
nextDirectory = path.join(directory, path.sep, '..')
;
if( folder == 'bower_components') {
moduleFolders++;
}
else if(folder == 'node_modules') {
moduleFolders++;
}
else if(folder == 'composer') {
moduleFolders++;
}
if(path.resolve(directory) == path.resolve(nextDirectory)) {
return (moduleFolders > 1);
}
// recurse downward
return walk(nextDirectory);
}
;
// start walk from current directory if none specified
directory = directory || (__dirname + path.sep);
return walk(directory);
},
createJSON: function(answers) {
var
json = {
paths: {
source: {},
output: {}
}
}
;
// add components
if(answers.components) {
json.components = answers.components;
}
// add rtl choice
if(answers.rtl) {
json.rtl = answers.rtl;
}
// add permissions
if(answers.permission) {
json.permission = answers.permission;
}
// add path to semantic
if(answers.semanticRoot) {
json.base = path.normalize(answers.semanticRoot);
}
// record version number to avoid re-installing on same version
json.version = release.version;
// add dist folder paths
if(answers.dist) {
answers.dist = path.normalize(answers.dist);
json.paths.output = {
packaged : path.normalize(answers.dist + '/'),
uncompressed : path.normalize(answers.dist + '/components/'),
compressed : path.normalize(answers.dist + '/components/'),
themes : path.normalize(answers.dist + '/themes/')
};
}
// add site path
if(answers.site) {
json.paths.source.site = path.normalize(answers.site + '/');
}
if(answers.packaged) {
json.paths.output.packaged = path.normalize(answers.packaged + '/');
}
if(answers.compressed) {
json.paths.output.compressed = path.normalize(answers.compressed + '/');
}
if(answers.uncompressed) {
json.paths.output.uncompressed = path.normalize(answers.uncompressed + '/');
}
return json;
},
// files cleaned up after install
setupFiles: [
'./src/theme.config.example',
'./semantic.json.example',
'./src/_site'
],
regExp: {
// used to match siteFolder variable in theme.less
siteVariable: /@siteFolder .*\'(.*)/mg
},
// source paths (when installing)
source: {
config : './semantic.json.example',
definitions : './src/definitions',
gulpFile : './gulpfile.js',
lessImport : './src/semantic.less',
site : './src/_site',
tasks : './tasks',
themeConfig : './src/theme.config.example',
themeImport : './src/theme.less',
themes : './src/themes',
defaultTheme : './src/themes/default',
userGulpFile : './tasks/config/npm/gulpfile.js'
},
// expected final filenames
files: {
config : 'semantic.json',
lessImport : 'src/semantic.less',
site : 'src/site',
themeConfig : 'src/theme.config',
themeImport : 'src/theme.less'
},
// folder paths to files relative to root
folders: {
config : './',
definitions : 'src/definitions/',
lessImport : 'src/',
modules : 'node_modules/',
site : 'src/site/',
tasks : 'tasks/',
themeConfig : 'src/',
themeImport : 'src/',
themes : 'src/themes/',
defaultTheme : 'default/' // only path that is relative to another directory and not root
},
// questions asked during install
questions: {
root: [
{
type : 'list',
name : 'useRoot',
message :
' \n' +
' {packageMessage} \n' +
' \n' +
' Is this your project folder?\n' +
' \x1b[92m{root}\x1b[0m \n' +
' \n ' +
'\n',
choices: [
{
name : 'Yes',
value : true
},
{
name : 'No, let me specify',
value : false
}
]
},
{
type : 'input',
name : 'customRoot',
message : 'Please enter the absolute path to your project root',
default : '/my/project/path',
when : when.changeRoot
},
{
type : 'input',
name : 'semanticRoot',
message : 'Where should we put Semantic UI inside your project?',
default : 'semantic/'
}
],
setup: [
{
type: 'list',
name: 'overwrite',
message: 'It looks like you have a semantic.json file already.',
when: when.hasConfig,
choices: [
{
name: 'Yes, extend my current settings.',
value: 'yes'
},
{
name: 'Skip install',
value: 'no'
}
]
},
{
type: 'list',
name: 'install',
message: 'Set-up Semantic UI',
when: when.allowOverwrite,
choices: [
{
name: 'Automatic (Use defaults locations and all components)',
value: 'auto'
},
{
name: 'Express (Set components and output folder)',
value: 'express'
},
{
name: 'Custom (Customize all src/dist values)',
value: 'custom'
}
]
},
{
type: 'checkbox',
name: 'components',
message: 'What components should we include in the package?',
// duplicated manually from tasks/defaults.js with additional property
choices: [
{ name: "reset", checked: true },
{ name: "site", checked: true },
{ name: "button", checked: true },
{ name: "container", checked: true },
{ name: "divider", checked: true },
{ name: "flag", checked: true },
{ name: "header", checked: true },
{ name: "icon", checked: true },
{ name: "image", checked: true },
{ name: "input", checked: true },
{ name: "label", checked: true },
{ name: "list", checked: true },
{ name: "loader", checked: true },
{ name: "rail", checked: true },
{ name: "reveal", checked: true },
{ name: "segment", checked: true },
{ name: "step", checked: true },
{ name: "breadcrumb", checked: true },
{ name: "form", checked: true },
{ name: "grid", checked: true },
{ name: "menu", checked: true },
{ name: "message", checked: true },
{ name: "table", checked: true },
{ name: "ad", checked: true },
{ name: "card", checked: true },
{ name: "comment", checked: true },
{ name: "feed", checked: true },
{ name: "item", checked: true },
{ name: "statistic", checked: true },
{ name: "accordion", checked: true },
{ name: "checkbox", checked: true },
{ name: "dimmer", checked: true },
{ name: "dropdown", checked: true },
{ name: "embed", checked: true },
{ name: "modal", checked: true },
{ name: "nag", checked: true },
{ name: "popup", checked: true },
{ name: "progress", checked: true },
{ name: "rating", checked: true },
{ name: "search", checked: true },
{ name: "shape", checked: true },
{ name: "sidebar", checked: true },
{ name: "sticky", checked: true },
{ name: "tab", checked: true },
{ name: "transition", checked: true },
{ name: "api", checked: true },
{ name: "form", checked: true },
{ name: "state", checked: true },
{ name: "visibility", checked: true }
],
when: when.notAuto
},
{
type: 'list',
name: 'changePermissions',
when: when.notAuto,
message: 'Should we set permissions on outputted files?',
choices: [
{
name: 'No',
value: false
},
{
name: 'Yes',
value: true
}
]
},
{
type: 'input',
name: 'permission',
message: 'What octal file permission should outputted files receive?',
default: defaults.permission,
when: when.changePermissions
},
{
type: 'list',
name: 'rtl',
message: 'Do you use a RTL (Right-To-Left) language?',
when: when.notAuto,
choices: [
{
name: 'No',
value: false
},
{
name: 'Yes',
value: true
},
{
name: 'Build Both',
value: 'both'
}
]
},
{
type: 'input',
name: 'dist',
message: 'Where should we output Semantic UI?',
default: defaults.paths.output.packaged,
filter: filter.removeTrailingSlash,
when: when.express
},
{
type: 'input',
name: 'site',
message: 'Where should we put your site folder?',
default: defaults.paths.source.site,
filter: filter.removeTrailingSlash,
when: when.custom
},
{
type: 'input',
name: 'packaged',
message: 'Where should we output a packaged version?',
default: defaults.paths.output.packaged,
filter: filter.removeTrailingSlash,
when: when.custom
},
{
type: 'input',
name: 'compressed',
message: 'Where should we output compressed components?',
default: defaults.paths.output.compressed,
filter: filter.removeTrailingSlash,
when: when.custom
},
{
type: 'input',
name: 'uncompressed',
message: 'Where should we output uncompressed components?',
default: defaults.paths.output.uncompressed,
filter: filter.removeTrailingSlash,
when: when.custom
}
],
cleanup: [
{
type: 'list',
name: 'cleanup',
message: 'Should we remove set-up files?',
choices: [
{
name: 'Yes (re-install will require redownloading semantic).',
value: 'yes'
},
{
name: 'No Thanks',
value: 'no'
}
]
},
{
type: 'list',
name: 'build',
message: 'Do you want to build Semantic now?',
choices: [
{
name: 'Yes',
value: 'yes'
},
{
name: 'No',
value: 'no'
}
]
},
],
site: [
{
type: 'list',
name: 'customize',
message: 'You have not yet customized your site, can we help you do that?',
choices: [
{
name: 'Yes, ask me a few questions',
value: true
},
{
name: 'No I\'ll do it myself',
value: false
}
]
},
{
type: 'list',
name: 'headerFont',
message: 'Select your header font',
choices: [
{
name: 'Helvetica Neue, Arial, sans-serif',
value: 'Helvetica Neue, Arial, sans-serif;'
},
{
name: 'Lato (Google Fonts)',
value: 'Lato'
},
{
name: 'Open Sans (Google Fonts)',
value: 'Open Sans'
},
{
name: 'Source Sans Pro (Google Fonts)',
value: 'Source Sans Pro'
},
{
name: 'Droid (Google Fonts)',
value: 'Droid'
},
{
name: 'I\'ll choose on my own',
value: false
}
],
when: when.customize
},
{
type: 'list',
name: 'pageFont',
message: 'Select your page font',
choices: [
{
name: 'Helvetica Neue, Arial, sans-serif',
value: 'Helvetica Neue, Arial, sans-serif;'
},
{
name: 'Lato (Import from Google Fonts)',
value: 'Lato'
},
{
name: 'Open Sans (Import from Google Fonts)',
value: 'Open Sans'
},
{
name: 'Source Sans Pro (Import from Google Fonts)',
value: 'Source Sans Pro'
},
{
name: 'Droid (Google Fonts)',
value: 'Droid'
},
{
name: 'I\'ll choose on my own',
value: false
}
],
when: when.customize
},
{
type: 'list',
name: 'fontSize',
message: 'Select your base font size',
default: '14px',
choices: [
{
name: '12px',
},
{
name: '13px',
},
{
name: '14px (Recommended)',
value: '14px'
},
{
name: '15px',
},
{
name: '16px',
},
{
name: 'I\'ll choose on my own',
value: false
}
],
when: when.customize
},
{
type: 'list',
name: 'primaryColor',
message: 'Select the closest name for your primary brand color',
default: '14px',
choices: [
{
name: 'Blue'
},
{
name: 'Green'
},
{
name: 'Orange'
},
{
name: 'Pink'
},
{
name: 'Purple'
},
{
name: 'Red'
},
{
name: 'Teal'
},
{
name: 'Yellow'
},
{
name: 'Black'
},
{
name: 'I\'ll choose on my own',
value: false
}
],
when: when.customize
},
{
type: 'input',
name: 'PrimaryHex',
message: 'Enter a hexcode for your primary brand color',
when: when.primaryColor
},
{
type: 'list',
name: 'secondaryColor',
message: 'Select the closest name for your secondary brand color',
default: '14px',
choices: [
{
name: 'Blue'
},
{
name: 'Green'
},
{
name: 'Orange'
},
{
name: 'Pink'
},
{
name: 'Purple'
},
{
name: 'Red'
},
{
name: 'Teal'
},
{
name: 'Yellow'
},
{
name: 'Black'
},
{
name: 'I\'ll choose on my own',
value: false
}
],
when: when.customize
},
{
type: 'input',
name: 'secondaryHex',
message: 'Enter a hexcode for your secondary brand color',
when: when.secondaryColor
}
]
},
settings: {
/* Rename Files */
rename: {
json : { extname : '.json' }
},
/* Copy Install Folders */
wrench: {
// overwrite existing files update & install (default theme / definition)
overwrite: {
forceDelete : true,
excludeHiddenUnix : true,
preserveFiles : false
},
// only create files that don't exist (site theme update)
merge: {
forceDelete : false,
excludeHiddenUnix : true,
preserveFiles : true
}
}
}
};