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.

756 lines
19 KiB

9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
  1. /*******************************
  2. Set-up
  3. *******************************/
  4. var
  5. fs = require('fs'),
  6. path = require('path'),
  7. defaults = require('../defaults'),
  8. release = require('./release'),
  9. requireDotFile = require('require-dot-file')
  10. ;
  11. /*******************************
  12. When to Ask
  13. *******************************/
  14. /* Preconditions for install questions */
  15. var when = {
  16. // path
  17. changeRoot: function(questions) {
  18. return (questions.useRoot !== undefined && questions.useRoot !== true);
  19. },
  20. // permissions
  21. changePermissions: function(questions) {
  22. return (questions.changePermissions && questions.changePermissions === true);
  23. },
  24. // install
  25. hasConfig: function() {
  26. return requireDotFile('semantic.json');
  27. },
  28. allowOverwrite: function(questions) {
  29. return (questions.overwrite === undefined || questions.overwrite == 'yes');
  30. },
  31. notAuto: function(questions) {
  32. return (questions.install !== 'auto' && (questions.overwrite === undefined || questions.overwrite == 'yes'));
  33. },
  34. custom: function(questions) {
  35. return (questions.install === 'custom' && (questions.overwrite === undefined || questions.overwrite == 'yes'));
  36. },
  37. express: function(questions) {
  38. return (questions.install === 'express' && (questions.overwrite === undefined || questions.overwrite == 'yes'));
  39. },
  40. // customize
  41. customize: function(questions) {
  42. return (questions.customize === true);
  43. },
  44. primaryColor: function(questions) {
  45. return (questions.primaryColor);
  46. },
  47. secondaryColor: function(questions) {
  48. return (questions.secondaryColor);
  49. }
  50. };
  51. /*******************************
  52. Response Filters
  53. *******************************/
  54. /* Filters to user input from install questions */
  55. var filter = {
  56. removeTrailingSlash: function(path) {
  57. return path.replace(/(\/$|\\$)+/mg, '');
  58. }
  59. };
  60. /*******************************
  61. Configuration
  62. *******************************/
  63. module.exports = {
  64. // check whether install is setup
  65. isSetup: function() {
  66. return when.hasConfig();
  67. },
  68. // checks if files are in a PM directory
  69. getPackageManager: function(directory) {
  70. var
  71. // returns last matching result (avoid sub-module detection)
  72. walk = function(directory) {
  73. var
  74. pathArray = directory.split(path.sep),
  75. folder = pathArray[pathArray.length - 1],
  76. nextDirectory = path.join(directory, path.sep, '..')
  77. ;
  78. if( folder == 'bower_components') {
  79. return {
  80. name: 'Bower',
  81. root: nextDirectory
  82. };
  83. }
  84. else if(folder == 'node_modules') {
  85. return {
  86. name: 'NPM',
  87. root: nextDirectory
  88. };
  89. }
  90. else if(folder == 'composer') {
  91. return {
  92. name: 'Composer',
  93. root: nextDirectory
  94. };
  95. }
  96. if(path.resolve(directory) == path.resolve(nextDirectory)) {
  97. return false;
  98. }
  99. // recurse downward
  100. return walk(nextDirectory);
  101. }
  102. ;
  103. // start walk from current directory if none specified
  104. directory = directory || (__dirname + path.sep);
  105. return walk(directory);
  106. },
  107. // checks if files is PMed submodule
  108. isSubModule: function(directory) {
  109. var
  110. moduleFolders = 0,
  111. walk = function(directory) {
  112. var
  113. pathArray = directory.split(path.sep),
  114. folder = pathArray[pathArray.length - 2],
  115. nextDirectory = path.join(directory, path.sep, '..')
  116. ;
  117. if( folder == 'bower_components') {
  118. moduleFolders++;
  119. }
  120. else if(folder == 'node_modules') {
  121. moduleFolders++;
  122. }
  123. else if(folder == 'composer') {
  124. moduleFolders++;
  125. }
  126. if(path.resolve(directory) == path.resolve(nextDirectory)) {
  127. return (moduleFolders > 1);
  128. }
  129. // recurse downward
  130. return walk(nextDirectory);
  131. }
  132. ;
  133. // start walk from current directory if none specified
  134. directory = directory || (__dirname + path.sep);
  135. return walk(directory);
  136. },
  137. createJSON: function(answers) {
  138. var
  139. json = {
  140. paths: {
  141. source: {},
  142. output: {}
  143. }
  144. }
  145. ;
  146. // add components
  147. if(answers.components) {
  148. json.components = answers.components;
  149. }
  150. // add rtl choice
  151. if(answers.rtl) {
  152. json.rtl = answers.rtl;
  153. }
  154. // add permissions
  155. if(answers.permission) {
  156. json.permission = answers.permission;
  157. }
  158. // add path to semantic
  159. if(answers.semanticRoot) {
  160. json.base = path.normalize(answers.semanticRoot);
  161. }
  162. // record version number to avoid re-installing on same version
  163. json.version = release.version;
  164. // add dist folder paths
  165. if(answers.dist) {
  166. answers.dist = path.normalize(answers.dist);
  167. json.paths.output = {
  168. packaged : path.normalize(answers.dist + '/'),
  169. uncompressed : path.normalize(answers.dist + '/components/'),
  170. compressed : path.normalize(answers.dist + '/components/'),
  171. themes : path.normalize(answers.dist + '/themes/')
  172. };
  173. }
  174. // add site path
  175. if(answers.site) {
  176. json.paths.source.site = path.normalize(answers.site + '/');
  177. }
  178. if(answers.packaged) {
  179. json.paths.output.packaged = path.normalize(answers.packaged + '/');
  180. }
  181. if(answers.compressed) {
  182. json.paths.output.compressed = path.normalize(answers.compressed + '/');
  183. }
  184. if(answers.uncompressed) {
  185. json.paths.output.uncompressed = path.normalize(answers.uncompressed + '/');
  186. }
  187. return json;
  188. },
  189. // files cleaned up after install
  190. setupFiles: [
  191. './src/theme.config.example',
  192. './semantic.json.example',
  193. './src/_site'
  194. ],
  195. regExp: {
  196. // used to match siteFolder variable in theme.less
  197. siteVariable: /@siteFolder .*\'(.*)/mg
  198. },
  199. // source paths (when installing)
  200. source: {
  201. config : './semantic.json.example',
  202. definitions : './src/definitions',
  203. gulpFile : './gulpfile.js',
  204. lessImport : './src/semantic.less',
  205. site : './src/_site',
  206. tasks : './tasks',
  207. themeConfig : './src/theme.config.example',
  208. themeImport : './src/theme.less',
  209. themes : './src/themes',
  210. defaultTheme : './src/themes/default',
  211. userGulpFile : './tasks/config/npm/gulpfile.js'
  212. },
  213. // expected final filenames
  214. files: {
  215. config : 'semantic.json',
  216. lessImport : 'src/semantic.less',
  217. site : 'src/site',
  218. themeConfig : 'src/theme.config',
  219. themeImport : 'src/theme.less'
  220. },
  221. // folder paths to files relative to root
  222. folders: {
  223. config : './',
  224. definitions : 'src/definitions/',
  225. lessImport : 'src/',
  226. modules : 'node_modules/',
  227. site : 'src/site/',
  228. tasks : 'tasks/',
  229. themeConfig : 'src/',
  230. themeImport : 'src/',
  231. themes : 'src/themes/',
  232. defaultTheme : 'default/' // only path that is relative to another directory and not root
  233. },
  234. // questions asked during install
  235. questions: {
  236. root: [
  237. {
  238. type : 'list',
  239. name : 'useRoot',
  240. message :
  241. ' \n' +
  242. ' {packageMessage} \n' +
  243. ' \n' +
  244. ' Is this your project folder?\n' +
  245. ' \x1b[92m{root}\x1b[0m \n' +
  246. ' \n ' +
  247. '\n',
  248. choices: [
  249. {
  250. name : 'Yes',
  251. value : true
  252. },
  253. {
  254. name : 'No, let me specify',
  255. value : false
  256. }
  257. ]
  258. },
  259. {
  260. type : 'input',
  261. name : 'customRoot',
  262. message : 'Please enter the absolute path to your project root',
  263. default : '/my/project/path',
  264. when : when.changeRoot
  265. },
  266. {
  267. type : 'input',
  268. name : 'semanticRoot',
  269. message : 'Where should we put Semantic UI inside your project?',
  270. default : 'semantic/'
  271. }
  272. ],
  273. setup: [
  274. {
  275. type: 'list',
  276. name: 'overwrite',
  277. message: 'It looks like you have a semantic.json file already.',
  278. when: when.hasConfig,
  279. choices: [
  280. {
  281. name: 'Yes, extend my current settings.',
  282. value: 'yes'
  283. },
  284. {
  285. name: 'Skip install',
  286. value: 'no'
  287. }
  288. ]
  289. },
  290. {
  291. type: 'list',
  292. name: 'install',
  293. message: 'Set-up Semantic UI',
  294. when: when.allowOverwrite,
  295. choices: [
  296. {
  297. name: 'Automatic (Use defaults locations and all components)',
  298. value: 'auto'
  299. },
  300. {
  301. name: 'Express (Set components and output folder)',
  302. value: 'express'
  303. },
  304. {
  305. name: 'Custom (Customize all src/dist values)',
  306. value: 'custom'
  307. }
  308. ]
  309. },
  310. {
  311. type: 'checkbox',
  312. name: 'components',
  313. message: 'What components should we include in the package?',
  314. // duplicated manually from tasks/defaults.js with additional property
  315. choices: [
  316. { name: "reset", checked: true },
  317. { name: "site", checked: true },
  318. { name: "button", checked: true },
  319. { name: "container", checked: true },
  320. { name: "divider", checked: true },
  321. { name: "flag", checked: true },
  322. { name: "header", checked: true },
  323. { name: "icon", checked: true },
  324. { name: "image", checked: true },
  325. { name: "input", checked: true },
  326. { name: "label", checked: true },
  327. { name: "list", checked: true },
  328. { name: "loader", checked: true },
  329. { name: "rail", checked: true },
  330. { name: "reveal", checked: true },
  331. { name: "segment", checked: true },
  332. { name: "step", checked: true },
  333. { name: "breadcrumb", checked: true },
  334. { name: "form", checked: true },
  335. { name: "grid", checked: true },
  336. { name: "menu", checked: true },
  337. { name: "message", checked: true },
  338. { name: "table", checked: true },
  339. { name: "ad", checked: true },
  340. { name: "card", checked: true },
  341. { name: "comment", checked: true },
  342. { name: "feed", checked: true },
  343. { name: "item", checked: true },
  344. { name: "statistic", checked: true },
  345. { name: "accordion", checked: true },
  346. { name: "checkbox", checked: true },
  347. { name: "dimmer", checked: true },
  348. { name: "dropdown", checked: true },
  349. { name: "embed", checked: true },
  350. { name: "modal", checked: true },
  351. { name: "nag", checked: true },
  352. { name: "popup", checked: true },
  353. { name: "progress", checked: true },
  354. { name: "rating", checked: true },
  355. { name: "search", checked: true },
  356. { name: "shape", checked: true },
  357. { name: "sidebar", checked: true },
  358. { name: "sticky", checked: true },
  359. { name: "tab", checked: true },
  360. { name: "transition", checked: true },
  361. { name: "api", checked: true },
  362. { name: "form", checked: true },
  363. { name: "state", checked: true },
  364. { name: "visibility", checked: true }
  365. ],
  366. when: when.notAuto
  367. },
  368. {
  369. type: 'list',
  370. name: 'changePermisions',
  371. when: when.notAuto,
  372. message: 'Should we set permissions on outputted files?',
  373. choices: [
  374. {
  375. name: 'No',
  376. value: false
  377. },
  378. {
  379. name: 'Yes',
  380. value: true
  381. },
  382. ]
  383. },
  384. {
  385. type: 'input',
  386. name: 'permission',
  387. message: 'What octal file permission should outputted files receive?',
  388. default: defaults.permission,
  389. when: when.changePermissions
  390. },
  391. {
  392. type: 'list',
  393. name: 'rtl',
  394. message: 'Do you use a RTL (Right-To-Left) language?',
  395. when: when.notAuto,
  396. choices: [
  397. {
  398. name: 'No',
  399. value: false
  400. },
  401. {
  402. name: 'Yes',
  403. value: true
  404. },
  405. {
  406. name: 'Build Both',
  407. value: 'both'
  408. }
  409. ]
  410. },
  411. {
  412. type: 'input',
  413. name: 'dist',
  414. message: 'Where should we output Semantic UI?',
  415. default: defaults.paths.output.packaged,
  416. filter: filter.removeTrailingSlash,
  417. when: when.express
  418. },
  419. {
  420. type: 'input',
  421. name: 'site',
  422. message: 'Where should we put your site folder?',
  423. default: defaults.paths.source.site,
  424. filter: filter.removeTrailingSlash,
  425. when: when.custom
  426. },
  427. {
  428. type: 'input',
  429. name: 'packaged',
  430. message: 'Where should we output a packaged version?',
  431. default: defaults.paths.output.packaged,
  432. filter: filter.removeTrailingSlash,
  433. when: when.custom
  434. },
  435. {
  436. type: 'input',
  437. name: 'compressed',
  438. message: 'Where should we output compressed components?',
  439. default: defaults.paths.output.compressed,
  440. filter: filter.removeTrailingSlash,
  441. when: when.custom
  442. },
  443. {
  444. type: 'input',
  445. name: 'uncompressed',
  446. message: 'Where should we output uncompressed components?',
  447. default: defaults.paths.output.uncompressed,
  448. filter: filter.removeTrailingSlash,
  449. when: when.custom
  450. }
  451. ],
  452. cleanup: [
  453. {
  454. type: 'list',
  455. name: 'cleanup',
  456. message: 'Should we remove set-up files?',
  457. choices: [
  458. {
  459. name: 'Yes (re-install will require redownloading semantic).',
  460. value: 'yes'
  461. },
  462. {
  463. name: 'No Thanks',
  464. value: 'no'
  465. }
  466. ]
  467. },
  468. {
  469. type: 'list',
  470. name: 'build',
  471. message: 'Do you want to build Semantic now?',
  472. choices: [
  473. {
  474. name: 'Yes',
  475. value: 'yes'
  476. },
  477. {
  478. name: 'No',
  479. value: 'no'
  480. }
  481. ]
  482. },
  483. ],
  484. site: [
  485. {
  486. type: 'list',
  487. name: 'customize',
  488. message: 'You have not yet customized your site, can we help you do that?',
  489. choices: [
  490. {
  491. name: 'Yes, ask me a few questions',
  492. value: true
  493. },
  494. {
  495. name: 'No I\'ll do it myself',
  496. value: false
  497. }
  498. ]
  499. },
  500. {
  501. type: 'list',
  502. name: 'headerFont',
  503. message: 'Select your header font',
  504. choices: [
  505. {
  506. name: 'Helvetica Neue, Arial, sans-serif',
  507. value: 'Helvetica Neue, Arial, sans-serif;'
  508. },
  509. {
  510. name: 'Lato (Google Fonts)',
  511. value: 'Lato'
  512. },
  513. {
  514. name: 'Open Sans (Google Fonts)',
  515. value: 'Open Sans'
  516. },
  517. {
  518. name: 'Source Sans Pro (Google Fonts)',
  519. value: 'Source Sans Pro'
  520. },
  521. {
  522. name: 'Droid (Google Fonts)',
  523. value: 'Droid'
  524. },
  525. {
  526. name: 'I\'ll choose on my own',
  527. value: false
  528. }
  529. ],
  530. when: when.customize
  531. },
  532. {
  533. type: 'list',
  534. name: 'pageFont',
  535. message: 'Select your page font',
  536. choices: [
  537. {
  538. name: 'Helvetica Neue, Arial, sans-serif',
  539. value: 'Helvetica Neue, Arial, sans-serif;'
  540. },
  541. {
  542. name: 'Lato (Import from Google Fonts)',
  543. value: 'Lato'
  544. },
  545. {
  546. name: 'Open Sans (Import from Google Fonts)',
  547. value: 'Open Sans'
  548. },
  549. {
  550. name: 'Source Sans Pro (Import from Google Fonts)',
  551. value: 'Source Sans Pro'
  552. },
  553. {
  554. name: 'Droid (Google Fonts)',
  555. value: 'Droid'
  556. },
  557. {
  558. name: 'I\'ll choose on my own',
  559. value: false
  560. }
  561. ],
  562. when: when.customize
  563. },
  564. {
  565. type: 'list',
  566. name: 'fontSize',
  567. message: 'Select your base font size',
  568. default: '14px',
  569. choices: [
  570. {
  571. name: '12px',
  572. },
  573. {
  574. name: '13px',
  575. },
  576. {
  577. name: '14px (Recommended)',
  578. value: '14px'
  579. },
  580. {
  581. name: '15px',
  582. },
  583. {
  584. name: '16px',
  585. },
  586. {
  587. name: 'I\'ll choose on my own',
  588. value: false
  589. }
  590. ],
  591. when: when.customize
  592. },
  593. {
  594. type: 'list',
  595. name: 'primaryColor',
  596. message: 'Select the closest name for your primary brand color',
  597. default: '14px',
  598. choices: [
  599. {
  600. name: 'Blue'
  601. },
  602. {
  603. name: 'Green'
  604. },
  605. {
  606. name: 'Orange'
  607. },
  608. {
  609. name: 'Pink'
  610. },
  611. {
  612. name: 'Purple'
  613. },
  614. {
  615. name: 'Red'
  616. },
  617. {
  618. name: 'Teal'
  619. },
  620. {
  621. name: 'Yellow'
  622. },
  623. {
  624. name: 'Black'
  625. },
  626. {
  627. name: 'I\'ll choose on my own',
  628. value: false
  629. }
  630. ],
  631. when: when.customize
  632. },
  633. {
  634. type: 'input',
  635. name: 'PrimaryHex',
  636. message: 'Enter a hexcode for your primary brand color',
  637. when: when.primaryColor
  638. },
  639. {
  640. type: 'list',
  641. name: 'secondaryColor',
  642. message: 'Select the closest name for your secondary brand color',
  643. default: '14px',
  644. choices: [
  645. {
  646. name: 'Blue'
  647. },
  648. {
  649. name: 'Green'
  650. },
  651. {
  652. name: 'Orange'
  653. },
  654. {
  655. name: 'Pink'
  656. },
  657. {
  658. name: 'Purple'
  659. },
  660. {
  661. name: 'Red'
  662. },
  663. {
  664. name: 'Teal'
  665. },
  666. {
  667. name: 'Yellow'
  668. },
  669. {
  670. name: 'Black'
  671. },
  672. {
  673. name: 'I\'ll choose on my own',
  674. value: false
  675. }
  676. ],
  677. when: when.customize
  678. },
  679. {
  680. type: 'input',
  681. name: 'secondaryHex',
  682. message: 'Enter a hexcode for your secondary brand color',
  683. when: when.secondaryColor
  684. }
  685. ]
  686. },
  687. settings: {
  688. /* Rename Files */
  689. rename: {
  690. json : { extname : '.json' },
  691. },
  692. /* Copy Install Folders */
  693. wrench: {
  694. // overwrite existing files update & install (default theme / definition)
  695. overwrite: {
  696. forceDelete : true,
  697. excludeHiddenUnix : true,
  698. preserveFiles : false
  699. },
  700. // only create files that don't exist (site theme update)
  701. merge: {
  702. forceDelete : false,
  703. excludeHiddenUnix : true,
  704. preserveFiles : true
  705. }
  706. }
  707. }
  708. };