From 51a7be2cb8e8b00a7758db0d6f730c8da72d291b Mon Sep 17 00:00:00 2001 From: Nixinova Date: Tue, 19 Mar 2024 13:13:06 +1300 Subject: [PATCH] Apply gitignores as folders are traversed Improves performance 3x. Also, ensure gitignore reading is done to spec: https://git-scm.com/docs/gitignore. --- changelog.md | 4 ++++ src/helpers/parse-gitignore.ts | 9 +++++++++ src/helpers/walk-tree.ts | 11 +++++++++++ src/index.ts | 22 ---------------------- 4 files changed, 24 insertions(+), 22 deletions(-) create mode 100644 src/helpers/parse-gitignore.ts diff --git a/changelog.md b/changelog.md index 49922c0..4475b57 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,9 @@ # Changelog +## Next +- Fixed gitignore file reading not pertaining exactly to spec. +- Improved performance by filtering out gitignored files during folder traversal. + ## 2.7.0 ### 2.7.0 (RC) diff --git a/src/helpers/parse-gitignore.ts b/src/helpers/parse-gitignore.ts new file mode 100644 index 0000000..fb0ccaf --- /dev/null +++ b/src/helpers/parse-gitignore.ts @@ -0,0 +1,9 @@ +export default function parseGitignore(content: string): string[] { + const readableData = content + // Remove comments unless escaped + .replace(/(? data); + return arrayData; +} diff --git a/src/helpers/walk-tree.ts b/src/helpers/walk-tree.ts index 8ccbd82..5c0dda6 100644 --- a/src/helpers/walk-tree.ts +++ b/src/helpers/walk-tree.ts @@ -1,6 +1,7 @@ import fs from 'fs'; import paths from 'path'; import ignore, { Ignore } from 'ignore'; +import parseGitignore from './parse-gitignore'; let allFiles: Set; let allFolders: Set; @@ -37,6 +38,7 @@ export default function walk(data: WalkInput): WalkOutput { if (folders.length === 1) { const folder = folders[0]; const localRoot = folderRoots[0].replace(commonRoot, '').replace(/^\//, ''); + // Get list of files and folders inside this folder const files = fs.readdirSync(folder).map(file => { // Create path relative to root @@ -45,6 +47,15 @@ export default function walk(data: WalkInput): WalkOutput { const isDir = fs.lstatSync(paths.resolve(commonRoot, base)).isDirectory(); return isDir ? `${base}/` : base; }); + + // Read and apply gitignores + const gitignoreFilename = paths.join(folder, '.gitignore'); + if (fs.existsSync(gitignoreFilename)) { + const gitignoreContents = fs.readFileSync(gitignoreFilename, 'utf-8'); + const ignoredPaths = parseGitignore(gitignoreContents); + ignored.add(ignoredPaths); + } + // Loop through files and folders for (const file of files) { // Create absolute path for disc operations diff --git a/src/index.ts b/src/index.ts index 666096b..8dac672 100644 --- a/src/index.ts +++ b/src/index.ts @@ -72,36 +72,14 @@ async function analyse(rawPaths?: string | string[], opts: T.Options = {}): Prom // Load file paths and folders let files: T.AbsFile[]; - let folders: T.AbsFolder[]; if (useRawContent) { // Uses raw file content files = input; - folders = ['']; } else { // Uses directory on disc const data = walk({ init: true, commonRoot, folderRoots: resolvedInput, folders: resolvedInput, ignored }); files = data.files; - folders = data.folders; - } - - // Load gitignore data and apply ignores rules - if (!useRawContent && opts.checkIgnored) { - const nestedIgnoreFiles = files.filter(file => file.endsWith('.gitignore')); - for (const ignoresFile of nestedIgnoreFiles) { - const relIgnoresFile = relPath(ignoresFile); - const relIgnoresFolder = paths.dirname(relIgnoresFile); - // Parse gitignores - const ignoresDataRaw = await readFile(ignoresFile); - const ignoresData = ignoresDataRaw.replace(/#.+|\s+$/gm, ''); - const absoluteIgnoresData = ignoresData - // '.file' -> 'root/*/.file' - .replace(/^(?=[^\s\/\\])/gm, localRoot(relIgnoresFolder) + '/*/') - // '/folder' -> 'root/folder' - .replace(/^[\/\\]/gm, localRoot(relIgnoresFolder) + '/') - ignored.add(absoluteIgnoresData); - files = filterOutIgnored(files, ignored); - } } // Fetch and normalise gitattributes data of all subfolders and save to metadata