Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 77 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@
},
"homepage": "https://github.com/larshp/abapmerge#readme",
"devDependencies": {
"@eslint/compat": "^1.2.0",
"@types/chai": "^4.3.20",
"@types/mocha": "^10.0.9",
"@types/node": "^24.3.0",
"@typescript-eslint/eslint-plugin": "^8.22.0",
"@typescript-eslint/parser": "^8.25.0",
"@eslint/compat": "^1.2.0",
"chai": "^4.5.0",
"eslint": "^9.21.0",
"mocha": "^10.7.3",
Expand All @@ -47,6 +47,7 @@
},
"dependencies": {
"commander": "^10.0.0",
"fast-xml-parser": "^5.0.8"
"fast-xml-parser": "^5.0.8",
"minimatch": "^10.0.3"
}
}
18 changes: 15 additions & 3 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import FileList from "./file_list";
import Merge from "./merge";
import { Command } from "commander";
import PackageInfo from "../package.json";
import { minimatch } from "minimatch";

interface ICliArgs {
entryFilename: string;
Expand All @@ -14,6 +15,7 @@ interface ICliArgs {
allowUnused: boolean;
newReportName: string;
outputFile: string;
excludePattern?: string;
}

export class Logic {
Expand All @@ -23,7 +25,13 @@ export class Logic {
return Logic.textFiles.has(path.extname(filepath).toLowerCase());
}

private static readFiles(dir: string, pre = ""): FileList {
private static shouldExcludeDir(dirPath: string, excludePattern?: string): boolean {
if (!excludePattern) return false;
const dirName = path.basename(dirPath);
return minimatch(dirName, excludePattern);
}

private static readFiles(dir: string, pre = "", excludePattern?: string): FileList {
const files = fs.readdirSync(dir);
const list = new FileList();

Expand All @@ -43,7 +51,9 @@ export class Logic {
}

} else {
list.concat(this.readFiles(filepath, path.join(pre, file)));
if (!this.shouldExcludeDir(filepath, excludePattern)) {
list.concat(this.readFiles(filepath, path.join(pre, file), excludePattern));
}
}
}

Expand All @@ -64,6 +74,7 @@ export class Logic {
"-c, --change-report-name <newreportname>",
"changes report name in REPORT clause in source code",
)
.option("-e, --exclude <pattern>", "exclude directories matching pattern (supports glob patterns)")
.arguments("<entrypoint>");

commander.exitOverride((err) => {
Expand Down Expand Up @@ -93,6 +104,7 @@ export class Logic {
allowUnused: cmdOpts.allowUnused,
newReportName: cmdOpts.changeReportName,
outputFile: cmdOpts.output,
excludePattern: cmdOpts.exclude,
};
}

Expand All @@ -107,7 +119,7 @@ export class Logic {

const entryObjectName = parsedArgs.entryFilename.split(".")[0];
output = Merge.merge(
Logic.readFiles(parsedArgs.entryDir),
Logic.readFiles(parsedArgs.entryDir, "", parsedArgs.excludePattern),
entryObjectName,
{
skipFUGR: parsedArgs.skipFUGR,
Expand Down
24 changes: 24 additions & 0 deletions test/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ describe("CLI parse arguments", () => {
newReportName: undefined,
allowUnused: false,
outputFile: undefined,
excludePattern: undefined,
};
chai.assert.isNotNull(parsedArgs);
chai.assert.deepEqual(parsedArgs, parsedArgsExpected);
Expand All @@ -58,6 +59,7 @@ describe("CLI parse arguments", () => {
newReportName: undefined,
allowUnused: false,
outputFile: undefined,
excludePattern: undefined,
};
chai.assert.isNotNull(parsedArgs);
chai.assert.deepEqual(parsedArgs, parsedArgsExpected);
Expand All @@ -76,6 +78,7 @@ describe("CLI parse arguments", () => {
newReportName: undefined,
allowUnused: false,
outputFile: undefined,
excludePattern: undefined,
};
chai.assert.isNotNull(parsedArgs);
chai.assert.deepEqual(parsedArgs, parsedArgsExpected);
Expand All @@ -96,6 +99,7 @@ describe("CLI parse arguments", () => {
newReportName: "znewname",
allowUnused: false,
outputFile: undefined,
excludePattern: undefined,
};
chai.assert.isNotNull(parsedArgs);
chai.assert.deepEqual(parsedArgs, parsedArgsExpected);
Expand All @@ -114,6 +118,26 @@ describe("CLI parse arguments", () => {
newReportName: undefined,
allowUnused: false,
outputFile: "some.file",
excludePattern: undefined,
};
chai.assert.isNotNull(parsedArgs);
chai.assert.deepEqual(parsedArgs, parsedArgsExpected);
});

it("exclude option", () => {
args.push("-e");
args.push("test*");
args.push(join(__dirname, "entry.abap"));
const parsedArgs = Logic.parseArgs(args);
const parsedArgsExpected = {
entryDir: __dirname,
entryFilename: "entry.abap",
skipFUGR: false,
noFooter: false,
newReportName: undefined,
allowUnused: false,
outputFile: undefined,
excludePattern: "test*",
};
chai.assert.isNotNull(parsedArgs);
chai.assert.deepEqual(parsedArgs, parsedArgsExpected);
Expand Down
45 changes: 45 additions & 0 deletions test/exclusion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {expect} from "chai";
import {Logic} from "../src/cli";

describe("Directory exclusion patterns", () => {
it("should exclude directories matching simple wildcard patterns", () => {
expect((Logic as any).shouldExcludeDir("/path/to/test", "test*")).to.equal(true);
expect((Logic as any).shouldExcludeDir("/path/to/testing", "test*")).to.equal(true);
expect((Logic as any).shouldExcludeDir("/path/to/production", "test*")).to.equal(false);
});

it("should exclude directories matching glob patterns with wildcards", () => {
expect((Logic as any).shouldExcludeDir("/path/to/temp", "*temp*")).to.equal(true);
expect((Logic as any).shouldExcludeDir("/path/to/temporary", "*temp*")).to.equal(true);
expect((Logic as any).shouldExcludeDir("/path/to/production", "*temp*")).to.equal(false);
});

it("should exclude directories matching brace expansion patterns", () => {
expect((Logic as any).shouldExcludeDir("/path/to/test", "{test*,build*}")).to.equal(true);
expect((Logic as any).shouldExcludeDir("/path/to/build", "{test*,build*}")).to.equal(true);
expect((Logic as any).shouldExcludeDir("/path/to/builddir", "{test*,build*}")).to.equal(true);
expect((Logic as any).shouldExcludeDir("/path/to/production", "{test*,build*}")).to.equal(false);
});

it("should handle case sensitive matching", () => {
expect((Logic as any).shouldExcludeDir("/path/to/test", "test*")).to.equal(true);
expect((Logic as any).shouldExcludeDir("/path/to/TEST", "test*")).to.equal(false);
expect((Logic as any).shouldExcludeDir("/path/to/Test", "test*")).to.equal(false);
expect((Logic as any).shouldExcludeDir("/path/to/TEST", "TEST*")).to.equal(true);
});

it("should not exclude when no pattern is provided", () => {
expect((Logic as any).shouldExcludeDir("/path/to/test", undefined)).to.equal(false);
expect((Logic as any).shouldExcludeDir("/path/to/test", "")).to.equal(false);
});

it("should handle exact directory name matches", () => {
expect((Logic as any).shouldExcludeDir("/path/to/node_modules", "node_modules")).to.equal(true);
expect((Logic as any).shouldExcludeDir("/path/to/node_modules_backup", "node_modules")).to.equal(false);
});

it("should only match directory basename not full path", () => {
expect((Logic as any).shouldExcludeDir("/test/path/to/production", "test*")).to.equal(false);
expect((Logic as any).shouldExcludeDir("/production/path/to/test", "test*")).to.equal(true);
});
});
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es2020",
"outDir": "build",
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
Expand Down