From 98acd0d88674bfc26279a9bc44417a1d11baf2ed Mon Sep 17 00:00:00 2001 From: Keivan Beigi Date: Tue, 21 Jul 2015 19:42:38 -0700 Subject: [PATCH] Added support for custom UI folder --- gulp/build.js | 12 +- gulp/clean.js | 4 +- gulp/errorHandler.js | 4 +- gulp/handlebars.js | 24 ++-- gulp/imageMin.js | 9 +- gulp/jshint.js | 8 +- gulp/less.js | 41 +++++-- gulp/paths.js | 70 +++++------ gulp/phantom.js | 4 +- gulp/start.js | 2 +- .../Frontend/Mappers/FaviconMapper.cs | 7 +- .../Frontend/Mappers/IndexHtmlMapper.cs | 2 +- .../Frontend/Mappers/LoginHtmlMapper.cs | 4 +- .../Frontend/Mappers/RobotsTxtMapper.cs | 7 +- .../Frontend/Mappers/StaticResourceMapper.cs | 7 +- .../Configuration/ConfigFileProvider.cs | 9 ++ webpack.config.js | 109 ++++++++++-------- 17 files changed, 192 insertions(+), 131 deletions(-) diff --git a/gulp/build.js b/gulp/build.js index c772abe68..23f457baf 100644 --- a/gulp/build.js +++ b/gulp/build.js @@ -6,7 +6,13 @@ require('./less'); require('./handlebars'); require('./copy'); -gulp.task('build', function () { - return runSequence('clean', - ['webpack', 'less', 'handlebars', 'copyHtml', 'copyContent', 'copyJs']); +gulp.task('build', function() { + return runSequence('clean', [ + 'webpack', + 'less', + 'handlebars', + 'copyHtml', + 'copyContent', + 'copyJs' + ]); }); diff --git a/gulp/clean.js b/gulp/clean.js index 61d8ca426..58f9c223f 100644 --- a/gulp/clean.js +++ b/gulp/clean.js @@ -3,6 +3,6 @@ var del = require('del'); var paths = require('./paths'); -gulp.task('clean', function (cb) { - del([paths.dest.root], cb); +gulp.task('clean', function(cb) { + del([paths.dest.root], cb); }); diff --git a/gulp/errorHandler.js b/gulp/errorHandler.js index eb6172df5..db24e1a66 100644 --- a/gulp/errorHandler.js +++ b/gulp/errorHandler.js @@ -1,7 +1,7 @@ module.exports = { - onError:function (error) { + onError : function(error) { //If you want details of the error in the console console.log(error.toString()); this.emit('end'); } -} \ No newline at end of file +}; \ No newline at end of file diff --git a/gulp/handlebars.js b/gulp/handlebars.js index cd3e5b18b..aab62f438 100644 --- a/gulp/handlebars.js +++ b/gulp/handlebars.js @@ -10,15 +10,18 @@ var stripbom = require('gulp-stripbom'); var paths = require('./paths.js'); -gulp.task('handlebars', function () { +gulp.task('handlebars', function() { - var coreStream = gulp.src([paths.src.templates, '!*/**/*Partial.*']) - .pipe(stripbom({ showLog: false })) + var coreStream = gulp.src([ + paths.src.templates, + '!*/**/*Partial.*' + ]) + .pipe(stripbom({ showLog : false })) .pipe(handlebars()) .pipe(declare({ - namespace: 'T', - noRedeclare: true, - processName: function (filePath) { + namespace : 'T', + noRedeclare : true, + processName : function(filePath) { filePath = path.relative(paths.src.root, filePath); @@ -30,12 +33,12 @@ gulp.task('handlebars', function () { })); var partialStream = gulp.src([paths.src.partials]) - .pipe(stripbom({ showLog: false })) + .pipe(stripbom({ showLog : false })) .pipe(handlebars()) .pipe(wrap('Handlebars.template(<%= contents %>)')) .pipe(wrap('Handlebars.registerPartial(<%= processPartialName(file.relative) %>, <%= contents %>)', {}, { - imports: { - processPartialName: function (fileName) { + imports : { + processPartialName : function(fileName) { return JSON.stringify( path.basename(fileName, '.js') ); @@ -43,8 +46,7 @@ gulp.task('handlebars', function () { } })); - - return streamqueue({ objectMode: true }, + return streamqueue({ objectMode : true }, partialStream, coreStream ).pipe(concat('templates.js')) diff --git a/gulp/imageMin.js b/gulp/imageMin.js index 0c51121bb..6c8236e03 100644 --- a/gulp/imageMin.js +++ b/gulp/imageMin.js @@ -2,14 +2,13 @@ var gulp = require('gulp'); var print = require('gulp-print'); var paths = require('./paths.js'); - -gulp.task('imageMin', function () { +gulp.task('imageMin', function() { var imagemin = require('gulp-imagemin'); return gulp.src(paths.src.images) .pipe(imagemin({ - progressive: false, - optimizationLevel :4, - svgoPlugins: [{removeViewBox: false}] + progressive : false, + optimizationLevel : 4, + svgoPlugins : [{ removeViewBox : false }] })) .pipe(print()) .pipe(gulp.dest(paths.src.content + 'Images/')); diff --git a/gulp/jshint.js b/gulp/jshint.js index dc8399272..650ad02c2 100644 --- a/gulp/jshint.js +++ b/gulp/jshint.js @@ -4,9 +4,11 @@ var stylish = require('jshint-stylish'); var cache = require('gulp-cached'); var paths = require('./paths.js'); - -gulp.task('jshint', function () { - return gulp.src([paths.src.scripts, paths.src.exclude.libs]) +gulp.task('jshint', function() { + return gulp.src([ + paths.src.scripts, + paths.src.exclude.libs + ]) .pipe(cache('jshint')) .pipe(jshint()) .pipe(jshint.reporter(stylish)); diff --git a/gulp/less.js b/gulp/less.js index a573f5812..e689cc08b 100644 --- a/gulp/less.js +++ b/gulp/less.js @@ -1,15 +1,35 @@ var gulp = require('gulp'); var less = require('gulp-less'); var print = require('gulp-print'); +var phantom = require('./phantom'); var livereload = require('gulp-livereload'); var paths = require('./paths'); var errorHandler = require('./errorHandler'); -gulp.task('less', function () { - return gulp.src([ +gulp.task('less', function() { + + var src = [ + paths.src.content + 'bootstrap.less', + paths.src.content + 'theme.less', + paths.src.content + 'overrides.less', + paths.src.root + 'Series/series.less', + paths.src.root + 'Activity/activity.less', + paths.src.root + 'AddSeries/addSeries.less', + paths.src.root + 'Calendar/calendar.less', + paths.src.root + 'Cells/cells.less', + paths.src.root + 'ManualImport/manualimport.less', + paths.src.root + 'Settings/settings.less', + paths.src.root + 'System/Logs/logs.less', + paths.src.root + 'System/Update/update.less', + paths.src.root + 'System/Info/info.less', + ]; + + if (phantom) { + src = [ paths.src.content + 'bootstrap.less', - paths.src.content + 'theme.less', + paths.src.content + 'angle.less', + paths.src.content + 'sonarr.less', paths.src.content + 'overrides.less', paths.src.root + 'Series/series.less', paths.src.root + 'Activity/activity.less', @@ -21,14 +41,17 @@ gulp.task('less', function () { paths.src.root + 'System/Logs/logs.less', paths.src.root + 'System/Update/update.less', paths.src.root + 'System/Info/info.less', - ]) + ] + } + + return gulp.src(src) .pipe(print()) .pipe(less({ - dumpLineNumbers: 'false', - compress: true, - yuicompress: true, - ieCompat: true, - strictImports: true + dumpLineNumbers : 'false', + compress : true, + yuicompress : true, + ieCompat : true, + strictImports : true })) .on('error', errorHandler.onError) .pipe(gulp.dest(paths.dest.content)) diff --git a/gulp/paths.js b/gulp/paths.js index ba56e4134..ca284c5a2 100644 --- a/gulp/paths.js +++ b/gulp/paths.js @@ -1,45 +1,45 @@ var phantom = require('./phantom'); var paths = { - src: { - root: './src/UI/', - templates: './src/UI/**/*.hbs', - html: './src/UI/*.html', - partials: './src/UI/**/*Partial.hbs', - scripts: './src/UI/**/*.js', - less: ['./src/UI/**/*.less'], - content: './src/UI/Content/', - images: './src/UI/Content/Images/**/*', - exclude: { - libs: '!./src/UI/JsLibraries/**' + src : { + root : './src/UI/', + templates : './src/UI/**/*.hbs', + html : './src/UI/*.html', + partials : './src/UI/**/*Partial.hbs', + scripts : './src/UI/**/*.js', + less : ['./src/UI/**/*.less'], + content : './src/UI/Content/', + images : './src/UI/Content/Images/**/*', + exclude : { + libs : '!./src/UI/JsLibraries/**' + } + }, + dest : { + root : './_output/UI/', + content : './_output/UI/Content/' } - }, - dest: { - root: './_output/UI/', - content: './_output/UI/Content/' - } }; if (phantom) { - paths = { - src: { - root: './src/UI.Phantom/', - templates: './src/UI.Phantom/**/*.hbs', - html: './src/UI.Phantom/*.html', - partials: './src/UI.Phantom/**/*Partial.hbs', - scripts: './src/UI.Phantom/**/*.js', - less: ['./src/UI.Phantom/**/*.less'], - content: './src/UI.Phantom/Content/', - images: './src/UI.Phantom/Content/Images/**/*', - exclude: { - libs: '!./src/UI.Phantom/JsLibraries/**' - } - }, - dest: { - root: './_output/UI.Phantom/', - content: './_output/UI.Phantom/Content/' - } - }; + paths = { + src : { + root : './src/UI.Phantom/', + templates : './src/UI.Phantom/**/*.hbs', + html : './src/UI.Phantom/*.html', + partials : './src/UI.Phantom/**/*Partial.hbs', + scripts : './src/UI.Phantom/**/*.js', + less : ['./src/UI.Phantom/**/*.less'], + content : './src/UI.Phantom/Content/', + images : './src/UI.Phantom/Content/Images/**/*', + exclude : { + libs : '!./src/UI.Phantom/JsLibraries/**' + } + }, + dest : { + root : './_output/UI.Phantom/', + content : './_output/UI.Phantom/Content/' + } + }; } module.exports = paths; diff --git a/gulp/phantom.js b/gulp/phantom.js index e9da44f6a..1aeb0385b 100644 --- a/gulp/phantom.js +++ b/gulp/phantom.js @@ -4,9 +4,11 @@ var phantom = false; process.argv.forEach(function (val, index, array) { - if(val=== '--phantom'){ + if (val === '--phantom') { phantom = true; } }); +console.log('Phantom:', phantom); + module.exports = phantom; \ No newline at end of file diff --git a/gulp/start.js b/gulp/start.js index 7a29d84b0..5b5f88044 100644 --- a/gulp/start.js +++ b/gulp/start.js @@ -84,7 +84,7 @@ gulp.task('getSonarr', function () { download(package.url, packagePath, function () { extract(packagePath, dirName, function () { // clean old binaries - console.log('Cleaning old binaries') + console.log('Cleaning old binaries'); del.sync(['./_output/*', '!./_output/UI/']); console.log('copying binaries to target'); gulp.src(dirName + '/NzbDrone/*.*') diff --git a/src/NzbDrone.Api/Frontend/Mappers/FaviconMapper.cs b/src/NzbDrone.Api/Frontend/Mappers/FaviconMapper.cs index 2947de2e8..c16b3b273 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/FaviconMapper.cs +++ b/src/NzbDrone.Api/Frontend/Mappers/FaviconMapper.cs @@ -3,17 +3,20 @@ using System.IO; using NLog; using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Core.Configuration; namespace NzbDrone.Api.Frontend.Mappers { public class FaviconMapper : StaticResourceMapperBase { private readonly IAppFolderInfo _appFolderInfo; + private readonly IConfigFileProvider _configFileProvider; - public FaviconMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, Logger logger) + public FaviconMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider,IConfigFileProvider configFileProvider, Logger logger) : base(diskProvider, logger) { _appFolderInfo = appFolderInfo; + _configFileProvider = configFileProvider; } public override string Map(string resourceUrl) @@ -27,7 +30,7 @@ namespace NzbDrone.Api.Frontend.Mappers var path = Path.Combine("Content", "Images", fileName); - return Path.Combine(_appFolderInfo.StartUpFolder, "UI", path); + return Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, path); } public override bool CanHandle(string resourceUrl) diff --git a/src/NzbDrone.Api/Frontend/Mappers/IndexHtmlMapper.cs b/src/NzbDrone.Api/Frontend/Mappers/IndexHtmlMapper.cs index fb1fac170..42adefe0d 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/IndexHtmlMapper.cs +++ b/src/NzbDrone.Api/Frontend/Mappers/IndexHtmlMapper.cs @@ -36,7 +36,7 @@ namespace NzbDrone.Api.Frontend.Mappers _configFileProvider = configFileProvider; _analyticsService = analyticsService; _cacheBreakProviderFactory = cacheBreakProviderFactory; - _indexPath = Path.Combine(appFolderInfo.StartUpFolder, "UI", "index.html"); + _indexPath = Path.Combine(appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, "index.html"); API_KEY = configFileProvider.ApiKey; URL_BASE = configFileProvider.UrlBase; diff --git a/src/NzbDrone.Api/Frontend/Mappers/LoginHtmlMapper.cs b/src/NzbDrone.Api/Frontend/Mappers/LoginHtmlMapper.cs index 33bb60257..4884402ce 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/LoginHtmlMapper.cs +++ b/src/NzbDrone.Api/Frontend/Mappers/LoginHtmlMapper.cs @@ -12,6 +12,7 @@ namespace NzbDrone.Api.Frontend.Mappers public class LoginHtmlMapper : StaticResourceMapperBase { private readonly IDiskProvider _diskProvider; + private readonly IConfigFileProvider _configFileProvider; private readonly Func _cacheBreakProviderFactory; private readonly string _indexPath; private static readonly Regex ReplaceRegex = new Regex("(?<=(?:href|src|data-main)=\").*?(?=\")", RegexOptions.Compiled | RegexOptions.IgnoreCase); @@ -27,8 +28,9 @@ namespace NzbDrone.Api.Frontend.Mappers : base(diskProvider, logger) { _diskProvider = diskProvider; + _configFileProvider = configFileProvider; _cacheBreakProviderFactory = cacheBreakProviderFactory; - _indexPath = Path.Combine(appFolderInfo.StartUpFolder, "UI", "login.html"); + _indexPath = Path.Combine(appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, "login.html"); URL_BASE = configFileProvider.UrlBase; } diff --git a/src/NzbDrone.Api/Frontend/Mappers/RobotsTxtMapper.cs b/src/NzbDrone.Api/Frontend/Mappers/RobotsTxtMapper.cs index 75a169912..855262a6c 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/RobotsTxtMapper.cs +++ b/src/NzbDrone.Api/Frontend/Mappers/RobotsTxtMapper.cs @@ -3,24 +3,27 @@ using System.IO; using NLog; using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Core.Configuration; namespace NzbDrone.Api.Frontend.Mappers { public class RobotsTxtMapper : StaticResourceMapperBase { private readonly IAppFolderInfo _appFolderInfo; + private readonly IConfigFileProvider _configFileProvider; - public RobotsTxtMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, Logger logger) + public RobotsTxtMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, IConfigFileProvider configFileProvider, Logger logger) : base(diskProvider, logger) { _appFolderInfo = appFolderInfo; + _configFileProvider = configFileProvider; } public override string Map(string resourceUrl) { var path = Path.Combine("Content", "robots.txt"); - return Path.Combine(_appFolderInfo.StartUpFolder, "UI", path); + return Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, path); } public override bool CanHandle(string resourceUrl) diff --git a/src/NzbDrone.Api/Frontend/Mappers/StaticResourceMapper.cs b/src/NzbDrone.Api/Frontend/Mappers/StaticResourceMapper.cs index c0ba9b889..f22ff9ce1 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/StaticResourceMapper.cs +++ b/src/NzbDrone.Api/Frontend/Mappers/StaticResourceMapper.cs @@ -2,17 +2,20 @@ using System.IO; using NLog; using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Core.Configuration; namespace NzbDrone.Api.Frontend.Mappers { public class StaticResourceMapper : StaticResourceMapperBase { private readonly IAppFolderInfo _appFolderInfo; + private readonly IConfigFileProvider _configFileProvider; - public StaticResourceMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, Logger logger) + public StaticResourceMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, IConfigFileProvider configFileProvider, Logger logger) : base(diskProvider, logger) { _appFolderInfo = appFolderInfo; + _configFileProvider = configFileProvider; } public override string Map(string resourceUrl) @@ -20,7 +23,7 @@ namespace NzbDrone.Api.Frontend.Mappers var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar); path = path.Trim(Path.DirectorySeparatorChar); - return Path.Combine(_appFolderInfo.StartUpFolder, "UI", path); + return Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, path); } public override bool CanHandle(string resourceUrl) diff --git a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs index 962eaa638..7bb9a16d2 100644 --- a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs +++ b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs @@ -37,6 +37,7 @@ namespace NzbDrone.Core.Configuration string ApiKey { get; } string SslCertHash { get; } string UrlBase { get; } + string UiFolder { get; } Boolean UpdateAutomatically { get; } UpdateMechanism UpdateMechanism { get; } String UpdateScriptPath { get; } @@ -215,6 +216,14 @@ namespace NzbDrone.Core.Configuration } } + public string UiFolder + { + get + { + return GetValue("UiFolder", "UI", false); + } + } + public bool UpdateAutomatically { get { return GetValueBoolean("UpdateAutomatically", false, false); } diff --git a/webpack.config.js b/webpack.config.js index e93e8436c..c265dd027 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,67 +1,74 @@ var path = require('path'); var stylish = require('jshint-stylish'); var webpack = require('webpack'); +var phantom = require('./gulp/phantom'); var uglifyJsPlugin = new webpack.optimize.UglifyJsPlugin(); +var uiFolder = 'UI'; + +if (phantom) { + uiFolder = 'UI.Phantom'; +} + module.exports = { entry: { vendor: 'vendor.js', main: 'main.js' }, - resolve : { - root : path.join(__dirname, 'src', 'UI'), - alias : { - 'vent' : 'vent', - 'backbone' : 'Shims/backbone', - 'moment' : 'JsLibraries/moment', - 'filesize' : 'JsLibraries/filesize', - 'handlebars' : 'Shims/handlebars', - 'handlebars.helpers' : 'JsLibraries/handlebars.helpers', - 'bootstrap' : 'JsLibraries/bootstrap', - 'backbone.deepmodel' : 'JsLibraries/backbone.deep.model', - 'backbone.pageable' : 'JsLibraries/backbone.pageable', - 'backbone-pageable' : 'JsLibraries/backbone.pageable', - 'backbone.validation' : 'Shims/backbone.validation', - 'backbone.modelbinder' : 'JsLibraries/backbone.modelbinder', - 'backbone.collectionview' : 'Shims/backbone.collectionview', - 'backgrid' : 'Shims/backgrid', - 'backgrid.paginator' : 'Shims/backgrid.paginator', - 'backgrid.selectall' : 'Shims/backbone.backgrid.selectall', - 'fullcalendar' : 'JsLibraries/fullcalendar', - 'backstrech' : 'JsLibraries/jquery.backstretch', - 'underscore' : 'JsLibraries/lodash.underscore', - 'marionette' : 'Shims/backbone.marionette', - 'signalR' : 'Shims/jquery.signalR', - 'jquery-ui' : 'JsLibraries/jquery-ui', - 'jquery.knob' : 'JsLibraries/jquery.knob', - 'jquery.easypiechart' : 'JsLibraries/jquery.easypiechart', - 'jquery.dotdotdot' : 'JsLibraries/jquery.dotdotdot', - 'messenger' : 'Shims/messenger', - 'jquery' : 'Shims/jquery', - 'typeahead' : 'JsLibraries/typeahead', - 'zero.clipboard' : 'JsLibraries/zero.clipboard', - 'bootstrap.tagsinput' : 'JsLibraries/bootstrap.tagsinput', - 'libs' : 'JsLibraries/' + resolve: { + root: path.join(__dirname, 'src', uiFolder), + alias: { + 'vent': 'vent', + 'backbone': 'Shims/backbone', + 'moment': 'JsLibraries/moment', + 'filesize': 'JsLibraries/filesize', + 'handlebars': 'Shims/handlebars', + 'handlebars.helpers': 'JsLibraries/handlebars.helpers', + 'bootstrap': 'JsLibraries/bootstrap', + 'backbone.deepmodel': 'JsLibraries/backbone.deep.model', + 'backbone.pageable': 'JsLibraries/backbone.pageable', + 'backbone-pageable': 'JsLibraries/backbone.pageable', + 'backbone.validation': 'Shims/backbone.validation', + 'backbone.modelbinder': 'JsLibraries/backbone.modelbinder', + 'backbone.collectionview': 'Shims/backbone.collectionview', + 'backgrid': 'Shims/backgrid', + 'backgrid.paginator': 'Shims/backgrid.paginator', + 'backgrid.selectall': 'Shims/backbone.backgrid.selectall', + 'fullcalendar': 'JsLibraries/fullcalendar', + 'backstrech': 'JsLibraries/jquery.backstretch', + 'underscore': 'JsLibraries/lodash.underscore', + 'marionette': 'Shims/backbone.marionette', + 'signalR': 'Shims/jquery.signalR', + 'jquery-ui': 'JsLibraries/jquery-ui', + 'jquery.knob': 'JsLibraries/jquery.knob', + 'jquery.easypiechart': 'JsLibraries/jquery.easypiechart', + 'jquery.dotdotdot': 'JsLibraries/jquery.dotdotdot', + 'messenger': 'Shims/messenger', + 'jquery': 'Shims/jquery', + 'typeahead': 'JsLibraries/typeahead', + 'zero.clipboard': 'JsLibraries/zero.clipboard', + 'bootstrap.tagsinput': 'JsLibraries/bootstrap.tagsinput', + 'libs': 'JsLibraries/' } }, - output : { - filename : '_output/UI/[name].js', - sourceMapFilename : '_output/UI/[name].map' + output: { + filename: '_output/' + uiFolder + '/[name].js', + sourceMapFilename: '_output/' + uiFolder + '/[name].map' }, - plugins : [ - new webpack.optimize.CommonsChunkPlugin({name: 'vendor'}) - ], + plugins: [ + new webpack.optimize.CommonsChunkPlugin({ name: 'vendor' }) + ], module: { - - //this doesn't work yet. wainting for https://github.com/spenceralger/rcloader/issues/5 - /*preLoaders: [ - { - test: /\.js$/, // include .js files - loader: "jshint-loader", - exclude: [/JsLibraries/,/node_modules/] - } - ] - */ - } + + //this doesn't work yet. wainting for https://github.com/spenceralger/rcloader/issues/5 + /*preLoaders: [ + { + test: /\.js$/, // include .js files + loader: "jshint-loader", + exclude: [/JsLibraries/,/node_modules/] + } + ] + */ + } };