UNPKG

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