/******************************* 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'); }, 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(); }, // 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' + ' \033[92m{root}\033[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: 'changePermisions', 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 } } } };