Search code examples
javascriptnode.jsgulpgulp-rename

Flattening parent directory but not subdirectories using gulp


I organized my code so that it has some keywords on the folder names such as _DIRECTIVE. My intention was to write a gulp task that recognize the folder naming pattern, using gulp.src("**/*_DIRECTIVE/**/*"). I want to make a copy of all folders (and its sub folders) which contains the _DIRECTVE keyword and put them in a separate folder.

I have a folder structure that looks like

src
   |-folder-name_1_DIRECTVE/
   | |-subfolder/
   | | |-subsubfolder/
   | |   |-file.js
   | |
   | |-file.js
   |
   |-folder/
   | |-folder-name_2_DIRECTVE/
   |   |-subfolder/
   |   | |-subsubfolder/
   |   |   |-file.js
   |   |
   |   |-file.js
   |
   |
   |-folder/
     |-subfolderfolder/
       |-folder-name_3_DIRECTVE/
         |-subfolder/
         | |-subsubfolder/
         |   |-file.js
         |
         |-file.js

Using gulp I want the output to be

output
       |-folder-name_1_DIRECTVE/
       | |-subfolder/
       | | |-subsubfolder/
       | |   |-file.js
       | |
       | |-file.js
       |
       |-folder-name_2_DIRECTVE/
       | |-subfolder/
       | | |-subsubfolder/
       | |   |-file.js
       | |
       | |-file.js
       |
       |-folder-name_3_DIRECTVE/
         |-subfolder/
         | |-subsubfolder/
         |   |-file.js
         |
         |-file.js

I tried to use gulp-flatten but it didn't help because it is also flattening the subfolders under my _DIRECTIVE folders.

Please help


Solution

  • You can use gulp-rename with a function callback to remove the corresponding parent folders:

    gulp.task('copy', function() {
      return gulp.src(['src/**/*_DIRECTIVE/**/*.js'])
        .pipe(rename(function(path) {
          path.dirname = path.dirname.replace(/^(.+[\\\/])?(?=[^\\\/]+_DIRECTIVE)/, '');
        }))
        .pipe(gulp.dest('output'));
    });
    

    Assuming a similar folder structure as in your question, with file names changed for clarity:

    $ find src -type f
    src/top-level_DIRECTIVE/directive1.js
    src/top-level_DIRECTIVE/subfolder1/subsubfolder1/directive1-sub.js
    src/folder-2/nested-2_DIRECTIVE/directive2.js
    src/folder-2/nested-2_DIRECTIVE/subfolder2/subsubfolder2/directive2-sub.js
    src/folder-3/double-nested/nested-3_DIRECTIVE/directive3.js
    src/folder-3/double-nested/nested-3_DIRECTIVE/subfolder3/subsubfolder3/directive3-sub.js
    
    $ gulp copy
    
    $ find output -type f
    output/top-level_DIRECTIVE/directive1.js
    output/top-level_DIRECTIVE/subfolder1/subsubfolder1/directive1-sub.js
    output/nested-2_DIRECTIVE/directive2.js
    output/nested-2_DIRECTIVE/subfolder2/subsubfolder2/directive2-sub.js
    output/nested-3_DIRECTIVE/directive3.js
    output/nested-3_DIRECTIVE/subfolder3/subsubfolder3/directive3-sub.js
    

    Explanation:

    path.dirname will be passed the filename relative to the "base" of your source pattern:

    • for gulp.src('src/**/*.js'):

      src/a.jspath.dirname == "a.js"
      src/nested/folder/b.jspath.dirname == "nested/folder/b.js"

    • for gulp.src('src/directives/**'):

      src/directives/tab-directive/tabs.jspath.dirname == "tab-directive/tabs.js"

    When you change the passed object inside the rename callback, the file path is appended to the output path:

    .pipe(gulp.rename(function (path) {
        path.basename = 'flat-' + path.basename;
    });
    // renames to:
    output/some-directory/flat-file1.js
    output/other-directory/flat-file2.js
    

    To remove parent directories of your *_DIRECTIVE directory from the path, use a regular expression:

    path.dirname = path.dirname.replace(/(.+[\\\/])?(?=[^\\\/]+_DIRECTIVE)/, '');
    
    /^(.+[\\\/])?(?=[^\\\/]+_DIRECTIVE)/
    
     ^                                    at the start of the string
      (        )?                         match an optional group
       .+                                 with 1 or more characters
         [\\\/]                           and ending with a directory separator (\ or /)
                 (?=                  )   followed by a group which is excluded from the match
                    [^\\\/]+              which has a folder-name (no \, /)
                            _DIRECTIVE    followed by a literal _DIRECTIVE