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

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 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. };