Allow reapeater services to be turned off (#6602)
[openemr.git] / gulpfile.js
blobf76a61c395e3f279e8256819a3a08f4c7de66871
1 "use strict";
3 // modules
4 const csso = require('gulp-csso');
5 const del = require('del');
6 const fs = require('fs');
7 const glob = require('glob');
8 const gap = require('gulp-append-prepend');
9 const replace = require('replace-in-file');
10 const gulp = require('gulp');
11 const argv = require('minimist')(process.argv.slice(2));
12 const gulpif = require('gulp-if');
13 const prefix = require('autoprefixer');
14 const postcss = require('gulp-postcss');
15 const rename = require('gulp-rename');
16 const sass = require('gulp-dart-sass');
17 const sourcemaps = require('gulp-sourcemaps');
18 const gulp_watch = require('gulp-watch');
19 const injector = require('gulp-inject-string');
20 const colors = require('colors');
22 // package.json
23 const packages = require('./package.json');
25 const logprefix = "[OpenEMR]".bold.cyan + " ";
27 // configuration
28 let config = {
29     all: [], // must always be empty
31     // Command Line Arguments
32     dev: argv['dev'],
33     build: argv['b'],
34     install: argv['i'],
36     // Source file locations
37     src: {
38         styles: {
39             style_tabs: 'interface/themes/tabs_style_*.scss',
40             style_uni: 'interface/themes/oe-styles/style_*.scss',
41             style_color: 'interface/themes/colors/*.scss',
42             directional: 'interface/themes/directional.scss',
43             misc: 'interface/themes/misc/**/*.scss'
44         }
45     },
46     dist: {
47         assets: 'public/assets/'
48     },
49     dest: {
50         themes: 'public/themes',
51         misc_themes: 'public/themes/misc'
52     }
55 if (config.install) {
56     console.log("\nCopying OpenEMR dependencies using Gulp".bold.yellow + "\n");
57 } else if (config.build) {
58     console.log("\nBuilding OpenEMR themes using Gulp".bold.yellow + "\n");
59 } else if (config.dev) {
60     console.log("\nBuilding OpenEMR themes using Dev Flag for Gulp".bold.yellow + "\n");
61 } else if (config.all) {
62     console.log("\nBuilding OpenEMR themes using All Flag for Gulp".bold.yellow + "\n");
63 } else {
64     // This is used for gulp watch & other misc things
65     console.log("\nRunning Gulp for OpenEMR".bold.yellow + "\n");
68 function log_error(isSuccess, err) {
69     isSuccess = false;
70     console.error(logprefix + "An error occured! Check the log for details.");
71     // Log error to console
72     console.error(err.toString().red);
73     // Kills gulp on error since if we keep running it will
74     // still fail
75     process.exit(1);
78 // Clean up lingering static themes
79 function clean(done) {
80     del.sync([config.dest.themes + "/*"]);
81     done();
84 // Parses command line arguments
85 function ingest(done) {
86     if (config.dev && typeof config.dev !== "boolean") {
87         config.dev = true;
88     }
89     done();
92 // definition of header for all compiled css
93 const autoGeneratedHeader = `
94 /*! This style sheet was autogenerated using gulp + scss
95  *  For usage instructions, see: https://github.com/openemr/openemr/blob/master/interface/README.md
96  */
99 // standard themes css compilation
100 function styles_style_uni() {
101     let isSuccess = true;
102     return gulp.src(config.src.styles.style_uni)
103         .pipe(gap.prependText('$compact-theme: false;\n'))
104         .pipe(injector.replace('// bs4import', '@import "../../../public/assets/bootstrap/scss/bootstrap";'))
105         .pipe(sourcemaps.init())
106         .pipe(sass().on('error', (err) => {
107             log_error(isSuccess, err);
108         }))
109         .pipe(postcss([prefix()]))
110         .pipe(gap.prependText(autoGeneratedHeader))
111         .pipe(gulpif(!config.dev, csso()))
112         .pipe(gulpif(!config.dev, sourcemaps.write()))
113         .on('error', (err) => {
114             log_error(isSuccess, err);
115         })
116         .pipe(gulp.dest(config.dest.themes))
117         .on('end', () => {
118             if (isSuccess) {
119                 console.log(logprefix + "Finished compiling OpenEMR base themes");
120             }
121         });
124 // standard themes compact css compilation
125 function styles_style_uni_compact() {
126     let isSuccess = true;
127     return gulp.src(config.src.styles.style_uni)
128         .pipe(gap.prependText('@import "../compact-theme-defaults";\n'))
129         .pipe(injector.replace('// bs4import', '@import "../oemr_compact_imports";'))
130         .pipe(sourcemaps.init())
131         .pipe(sass().on('error', (err) => {
132             log_error(isSuccess, err);
133         }))
134         .pipe(postcss([prefix()]))
135         .pipe(gap.prependText(autoGeneratedHeader))
136         .pipe(gulpif(!config.dev, csso()))
137         .pipe(gulpif(!config.dev, sourcemaps.write()))
138         .pipe(rename({
139             prefix: "compact_"
140         }))
141         .on('error', (err) => {
142             log_error(isSuccess, err);
143         })
144         .pipe(gulp.dest(config.dest.themes))
145         .on('end', () => {
146             if (isSuccess) {
147                 console.log(logprefix + "Finished compiling OpenEMR compact base themes");
148             }
149         });
152 // color themes css compilation
153 function styles_style_color() {
154     let isSuccess = true;
155     return gulp.src(config.src.styles.style_color)
156         .pipe(gap.prependText('$compact-theme: false;\n'))
157         .pipe(injector.replace('// bs4import', '@import "../../../public/assets/bootstrap/scss/bootstrap";'))
158         .pipe(sourcemaps.init())
159         .pipe(sass().on('error', (err) => {
160             log_error(isSuccess, err);
161         }))
162         .pipe(postcss([prefix()]))
163         .pipe(gap.prependText(autoGeneratedHeader))
164         .pipe(gulpif(!config.dev, csso()))
165         .pipe(gulpif(!config.dev, sourcemaps.write()))
166         .on('error', (err) => {
167             log_error(isSuccess, err);
168         })
169         .pipe(gulp.dest(config.dest.themes))
170         .on('end', () => {
171             if (isSuccess) {
172                 console.log(logprefix + "Finished compiling OpenEMR color themes");
173             }
174         });
177 // color themes compact css compilation
178 function styles_style_color_compact() {
179     let isSuccess = true;
180     return gulp.src(config.src.styles.style_color)
181         .pipe(gap.prependText('@import "../compact-theme-defaults";\n'))
182         .pipe(injector.replace('// bs4import', '@import "../oemr_compact_imports";'))
183         .pipe(sourcemaps.init())
184         .pipe(sass().on('error', (err) => {
185             log_error(isSuccess, err);
186         }))
187         .pipe(postcss([prefix()]))
188         .pipe(gap.prependText(autoGeneratedHeader))
189         .pipe(gulpif(!config.dev, csso()))
190         .pipe(gulpif(!config.dev, sourcemaps.write()))
191         .pipe(rename({
192             prefix: "compact_"
193         }))
194         .on('error', (err) => {
195             log_error(isSuccess, err);
196         })
197         .pipe(gulp.dest(config.dest.themes))
198         .on('end', () => {
199             if (isSuccess) {
200                 console.log(logprefix + "Finished compiling OpenEMR compact color themes");
201             }
202         });
205 // Tabs CSS compilation
206 function styles_style_tabs() {
207     let isSuccess = true;
208     return gulp.src(config.src.styles.style_tabs)
209         .pipe(sourcemaps.init())
210         .pipe(sass().on('error', (err) => {
211             log_error(isSuccess, err);
212         }))
213         .pipe(postcss([prefix()]))
214         .pipe(gap.prependText(autoGeneratedHeader))
215         .pipe(gulpif(!config.dev, csso()))
216         .pipe(gulpif(!config.dev, sourcemaps.write()))
217         .on('error', (err) => {
218             log_error(isSuccess, err);
219         })
220         .pipe(gulp.dest(config.dest.themes))
221         .on('end', () => {
222             if (isSuccess) {
223                 console.log(logprefix + "Finished compiling OpenEMR tab navigation styles");
224             }
225         });
228 // For anything else that needs to be moved, use misc themes
229 function styles_style_misc() {
230     let isSuccess = true;
231     return gulp.src(config.src.styles.misc)
232         .pipe(sourcemaps.init())
233         .pipe(sass().on('error', (err) => {
234             log_error(isSuccess, err);
235         }))
236         .pipe(postcss([prefix()]))
237         .pipe(gap.prependText(autoGeneratedHeader))
238         .pipe(gulpif(!config.dev, csso()))
239         .pipe(gulpif(!config.dev, sourcemaps.write()))
240         .on('error', (err) => {
241             log_error(isSuccess, err);
242         })
243         .pipe(gulp.dest(config.dest.misc_themes))
244         .on('end', () => {
245             if (isSuccess) {
246                 console.log(logprefix + "Finished compiling miscellaneous styles");
247             }
248         });
251 // rtl standard themes css compilation
252 function rtl_style_uni() {
253     let isSuccess = true;
254     return gulp.src(config.src.styles.style_uni)
255         .pipe(gap.prependText('$compact-theme: false;\n$dir: rtl;\n@import "../rtl";\n')) // watch out for this relative path!
256         .pipe(gap.appendText('@include if-rtl { @include rtl_style; #bigCal { border-right: 1px solid $black !important; } }\n'))
257         .pipe(injector.replace('// bs4import', '@import "../oemr-rtl";'))
258         .pipe(sourcemaps.init())
259         .pipe(sass().on('error', (err) => {
260             log_error(isSuccess, err);
261         }))
262         .pipe(postcss([prefix()]))
263         .pipe(gap.prependText(autoGeneratedHeader))
264         .pipe(gulpif(!config.dev, csso()))
265         .pipe(gulpif(!config.dev, sourcemaps.write()))
266         .pipe(rename({
267             prefix: "rtl_"
268         }))
269         .on('error', (err) => {
270             log_error(isSuccess, err);
271         })
272         .pipe(gulp.dest(config.dest.themes))
273         .on('end', () => {
274             if (isSuccess) {
275                 console.log(logprefix + "Finished compiling RTL base themes");
276             }
277         });
280 // rtl standard themes compact css compilation
281 function rtl_style_uni_compact() {
282     let isSuccess = true;
283     return gulp.src(config.src.styles.style_uni)
284         .pipe(gap.prependText('@import "../compact-theme-defaults";\n'))
285         .pipe(gap.prependText('$dir: rtl;\n@import "../rtl";\n')) // watch out for this relative path!
286         .pipe(gap.appendText('@include if-rtl { @include rtl_style; #bigCal { border-right: 1px solid $black !important; } }\n'))
287         .pipe(injector.replace('// bs4import', '@import "../oemr_rtl_compact_imports";'))
288         .pipe(sourcemaps.init())
289         .pipe(sass().on('error', (err) => {
290             log_error(isSuccess, err);
291         }))
292         .pipe(postcss([prefix()]))
293         .pipe(gap.prependText(autoGeneratedHeader))
294         .pipe(gulpif(!config.dev, csso()))
295         .pipe(gulpif(!config.dev, sourcemaps.write()))
296         .pipe(rename({
297             prefix: "rtl_compact_"
298         }))
299         .on('error', (err) => {
300             log_error(isSuccess, err);
301         })
302         .pipe(gulp.dest(config.dest.themes))
303         .on('end', () => {
304             if (isSuccess) {
305                 console.log(logprefix + "Finished compiling RTL base compact themes");
306             }
307         });
310 // rtl color themes css compilation
311 function rtl_style_color() {
312     let isSuccess = true;
313     return gulp.src(config.src.styles.style_color)
314         .pipe(gap.prependText('$compact-theme: false;\n$dir: rtl;\n@import "../rtl";\n')) // watch out for this relative path!
315         .pipe(gap.appendText('@include if-rtl { @include rtl_style; #bigCal { border-right: 1px solid $black !important; } }\n'))
316         .pipe(injector.replace('// bs4import', '@import "../oemr-rtl";'))
317         .pipe(sourcemaps.init())
318         .pipe(sass().on('error', (err) => {
319             log_error(isSuccess, err);
320         }))
321         .pipe(postcss([prefix()]))
322         .pipe(gap.prependText(autoGeneratedHeader))
323         .pipe(gulpif(!config.dev, csso()))
324         .pipe(gulpif(!config.dev, sourcemaps.write()))
325         .pipe(rename({
326             prefix: "rtl_"
327         }))
328         .on('error', (err) => {
329             log_error(isSuccess, err);
330         })
331         .pipe(gulp.dest(config.dest.themes))
332         .on('end', () => {
333             if (isSuccess) {
334                 console.log(logprefix + "Compiled OpenEMR RTL color themes");
335             }
336         });
339 // rtl color themes compact css compilation
340 function rtl_style_color_compact() {
341     let isSuccess = true;
342     return gulp.src(config.src.styles.style_color)
343         .pipe(gap.prependText('@import "../compact-theme-defaults";\n'))
344         .pipe(gap.prependText('$dir: rtl;\n@import "../rtl";\n')) // watch out for this relative path!
345         .pipe(gap.appendText('@include if-rtl { @include rtl_style; #bigCal { border-right: 1px solid $black !important; } }\n'))
346         .pipe(injector.replace('// bs4import', '@import "../oemr_rtl_compact_imports";'))
347         .pipe(sourcemaps.init())
348         .pipe(sass().on('error', (err) => {
349             log_error(isSuccess, err);
350         }))
351         .pipe(postcss([prefix()]))
352         .pipe(gap.prependText(autoGeneratedHeader))
353         .pipe(gulpif(!config.dev, csso()))
354         .pipe(gulpif(!config.dev, sourcemaps.write()))
355         .pipe(rename({
356             prefix: "rtl_compact_"
357         }))
358         .on('error', (err) => {
359             log_error(isSuccess, err);
360         })
361         .pipe(gulp.dest(config.dest.themes))
362         .on('end', () => {
363             if (isSuccess) {
364                 console.log(logprefix + "Finished compiling RTL compact color themes");
365             }
366         });
369 // rtl standard themes css compilation
370 function rtl_style_tabs() {
371     let isSuccess = true;
372     return gulp.src(config.src.styles.style_tabs)
373         .pipe(gap.prependText('$dir: rtl;\n@import "rtl";\n')) // watch out for this relative path!
374         .pipe(sourcemaps.init())
375         .pipe(sass().on('error', (err) => {
376             log_error(isSuccess, err);
377         }))
378         .pipe(postcss([prefix()]))
379         .pipe(gap.prependText(autoGeneratedHeader))
380         .pipe(gulpif(!config.dev, csso()))
381         .pipe(gulpif(!config.dev, sourcemaps.write()))
382         .pipe(rename({
383             prefix: "rtl_"
384         }))
385         .on('error', (err) => {
386             log_error(isSuccess, err);
387         })
388         .pipe(gulp.dest(config.dest.themes))
389         .on('end', () => {
390             if (isSuccess) {
391                 console.log(logprefix + "Finished compiling RTL tabs styles");
392             }
393         });
396 // For anything else that needs to be moved, use misc themes
397 function rtl_style_misc() {
398     let isSuccess = true;
399     return gulp.src(config.src.styles.misc)
400         .pipe(gap.prependText('$dir: rtl;\n')) // Simply a flag here due to a hierarchy possibly being created
401         .pipe(sourcemaps.init())
402         .pipe(sass().on('error', (err) => {
403             log_error(isSuccess, err);
404         }))
405         .pipe(postcss([prefix()]))
406         .pipe(gap.prependText(autoGeneratedHeader))
407         .pipe(gulpif(!config.dev, csso()))
408         .pipe(gulpif(!config.dev, sourcemaps.write()))
409         .pipe(rename({
410             prefix: "rtl_"
411         }))
412         .on('error', (err) => {
413             log_error(isSuccess, err);
414         })
415         .pipe(gulp.dest(config.dest.misc_themes))
416         .on('end', () => {
417             if (isSuccess) {
418                 console.log(logprefix + "Compiled rest of RTL SCSS");
419             }
420         });
423 // compile themes
424 const styles = gulp.parallel(styles_style_color, styles_style_color_compact, styles_style_uni, styles_style_uni_compact, styles_style_tabs, styles_style_misc, rtl_style_color, rtl_style_color_compact, rtl_style_uni, rtl_style_uni_compact, rtl_style_tabs, rtl_style_misc);
426 // Copies (and distills, if possible) assets from node_modules to public/assets
427 function install(done) {
428     console.log(logprefix + "Running OpenEMR gulp install task...");
429     // combine dependencies and napa sources into one object
430     const dependencies = packages.dependencies;
431     for (let key in packages.napa) {
432         if (packages.napa.hasOwnProperty(key)) {
433             dependencies[key] = packages.napa[key];
434         }
435     }
437     for (let key in dependencies) {
438         // check if the property/key is defined in the object itself, not in parent
439         if (dependencies.hasOwnProperty(key)) {
440             if (key == 'dwv') {
441                 // dwv is special and need to copy dist, decoders and locales
442                 gulp.src('node_modules/' + key + '/dist/**/*')
443                     .pipe(gulp.dest(config.dist.assets + key + '/dist'));
444                 gulp.src('node_modules/' + key + '/decoders/**/*')
445                     .pipe(gulp.dest(config.dist.assets + key + '/decoders'));
446                 gulp.src('node_modules/' + key + '/locales/**/*')
447                     .pipe(gulp.dest(config.dist.assets + key + '/locales'));
448             } else if (key == 'bootstrap' || key == 'bootstrap-rtl') {
449                 // bootstrap and bootstrap-v4-rtl are special and need to copy dist and scss
450                 gulp.src('node_modules/' + key + '/dist/**/*')
451                     .pipe(gulp.dest(config.dist.assets + key + '/dist'));
452                 gulp.src('node_modules/' + key + '/scss/**/*')
453                     .pipe(gulp.dest(config.dist.assets + key + '/scss'));
454             } else if (key == '@fortawesome/fontawesome-free') {
455                 // @fortawesome/fontawesome-free is special and need to copy css, scss, and webfonts
456                 gulp.src('node_modules/' + key + '/css/**/*')
457                     .pipe(gulp.dest(config.dist.assets + key + '/css'));
458                 gulp.src('node_modules/' + key + '/scss/**/*')
459                     .pipe(gulp.dest(config.dist.assets + key + '/scss'));
460                 gulp.src('node_modules/' + key + '/webfonts/**/*')
461                     .pipe(gulp.dest(config.dist.assets + key + '/webfonts'));
462             } else if (key == "moment") {
463                 gulp.src('node_modules/' + key + '/min/**/*')
464                     .pipe(gulp.dest(config.dist.assets + key + '/min'));
465                 gulp.src('node_modules/' + key + '/moment.js')
466                     .pipe(gulp.dest(config.dist.assets + key));
467             } else if (fs.existsSync('node_modules/' + key + '/dist')) {
468                 // only copy dist directory, if it exists
469                 gulp.src('node_modules/' + key + '/dist/**/*')
470                     .pipe(gulp.dest(config.dist.assets + key + '/dist'));
471             } else {
472                 // copy everything
473                 gulp.src('node_modules/' + key + '/**/*')
474                     .pipe(gulp.dest(config.dist.assets + key));
475             }
476         }
477     }
479     console.log(logprefix + "Finished running OpenEMR gulp install task");
480     done();
483 function watch() {
484     let isSuccess = true;
485     console.log(logprefix + "Running gulp watch task...");
486     // watch all changes and re-run styles
487     gulp.watch('./interface/**/*.scss', {
488             interval: 1000,
489             mode: 'poll'
490         }, styles)
491         .on('error', (err) => {
492             log_error(isSuccess, err);
493         });
495     // watch php separately since autoprefix is not needed
496     gulp_watch('./interface/themes/*.php', {
497             ignoreInitial: false
498         })
499         .pipe(gulp.dest(config.dest.themes))
500         .on('error', (err) => {
501             log_error(isSuccess, err);
502         });
504     // watch all changes to css files in themes and
505     // autoprefix them before copying to public
506     return gulp_watch('./interface/themes/*.css', {
507             ignoreInitial: false
508         })
509         .pipe(postcss([prefix()]))
510         .on('error', (err) => {
511             log_error(isSuccess, err);
512         })
513         .pipe(gulp.dest(config.dest.themes))
514         .on('end', () => {
515             if (isSuccess) {
516                 console.log(logprefix + "Finished running gulp watch task");
517             }
518         });
521 function sync() {
522     let isSuccess = true;
523     console.log(logprefix + "Running gulp sync task...");
524     // copy all leftover root-level components to the theme directory
525     // hoping this is only temporary
526     // Copy php file separately since we don't need to autoprefix them
527     gulp.src(['interface/themes/*.php'])
528         .pipe(gulp.dest(config.dest.themes))
529         .on('error', (err) => {
530             log_error(isSuccess, err);
531         });
533     // Copy CSS files and autoprefix them
534     return gulp.src(['interface/themes/*.css'])
535         .pipe(postcss([prefix()]))
536         .on('error', (err) => {
537             log_error(isSuccess, err);
538         })
539         .pipe(gulp.dest(config.dest.themes))
540         .on('end', () => {
541             if (isSuccess) {
542                 console.log(logprefix + "Finished running gulp sync task");
543             }
544         });
547 // Export watch task
548 exports.watch = watch;
550 // Export pertinent default task
551 // - Note that the default task runs if no other task is chosen,
552 //    which is generally how this script is always used (except in
553 //    rare case where the user is running the watch task).
554 if (config.install) {
555     exports.default = gulp.series(install);
556 } else {
557     exports.default = gulp.series(clean, ingest, styles, sync);