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.

762 lines
19 KiB

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