Skip to content

Commit

Permalink
Added --exclude-regex and --exclude-file (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
max-leuthaeuser authored Nov 26, 2024
1 parent ddbd431 commit af964b8
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 19 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@joernio/astgen",
"version": "3.20.0",
"version": "3.21.0",
"description": "Generate JS/TS AST in json format with Babel",
"exports": "./index.js",
"keywords": [
Expand Down
4 changes: 3 additions & 1 deletion src/Defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ export const IGNORE_DIRS: string[] = [
"build",
];

export const IGNORE_FILE_PATTERN: RegExp = new RegExp("(conf|test|spec|[.-]min|\\.d)\\.(js|ts|jsx|tsx)$", "i");
export const IGNORE_FILE_PATTERN: RegExp =
new RegExp("(chunk-vendors|app~|mock|e2e|conf|test|spec|[.-]min|\\.d)\\.(js|ts|jsx|tsx)$", "i");

export const MAX_LOC_IN_FILE: number = 50000;

export const BABEL_PARSER_OPTIONS: babelParser.ParserOptions = {
Expand Down
39 changes: 32 additions & 7 deletions src/FileUtils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import Options from "./Options";
import * as Defaults from "./Defaults";

import {readdirpPromise} from 'readdirp';
import * as fs from "node:fs";
import nReadlines from "n-readlines";
import * as path from "node:path"

function countFileLines(filePath: string): number {
const broadbandLines = new nReadlines(filePath);
Expand All @@ -13,9 +15,29 @@ function countFileLines(filePath: string): number {
return lineNumber
}

function ignoreDirectory(dirName: string): boolean {
function dirIsInIgnorePath(options: Options, fullPath: string, ignorePath: string): boolean {
if (path.isAbsolute(ignorePath)) {
return fullPath.startsWith(ignorePath)
} else {
const absIgnorePath = path.join(options.src, ignorePath)
return fullPath.startsWith(absIgnorePath)
}
}

function fileIsInIgnorePath(options: Options, fullPath: string, ignorePath: string): boolean {
if (path.isAbsolute(ignorePath)) {
return fullPath == ignorePath
} else {
const absIgnorePath = path.join(options.src, ignorePath)
return fullPath == absIgnorePath
}
}

function ignoreDirectory(options: Options, dirName: string, fullPath: string): boolean {
return dirName.startsWith(".") ||
dirName.startsWith("__") ||
options["exclude-file"].some((e: string) => dirIsInIgnorePath(options, fullPath, e)) ||
options["exclude-regex"]?.test(fullPath) ||
Defaults.IGNORE_DIRS.includes(dirName.toLowerCase())
}

Expand All @@ -35,19 +57,22 @@ function isTooLarge(fileWithDir: string): boolean {
return false;
}

function ignoreFile(fileName: string, fileWithDir: string, extensions: string[]): boolean {
function ignoreFile(options: Options, fileName: string, fullPath: string, extensions: string[]): boolean {
return !extensions.some((e: string) => fileName.endsWith(e)) ||
fileName.startsWith(".") ||
fileName.startsWith("__") ||
Defaults.IGNORE_FILE_PATTERN.test(fileName) ||
isEmscripten(fileWithDir) ||
isTooLarge(fileWithDir)
options["exclude-file"].some((e: string) => fileIsInIgnorePath(options, fullPath, e)) ||
options["exclude-regex"]?.test(fullPath) ||
isEmscripten(fullPath) ||
isTooLarge(fullPath)
}

export async function filesWithExtensions(dir: string, extensions: string[]): Promise<string[]> {
export async function filesWithExtensions(options: Options, extensions: string[]): Promise<string[]> {
const dir = options.src
const files = await readdirpPromise(dir, {
fileFilter: (f) => !ignoreFile(f.basename, f.fullPath, extensions),
directoryFilter: (d) => !ignoreDirectory(d.basename),
fileFilter: (f) => !ignoreFile(options, f.basename, f.fullPath, extensions),
directoryFilter: (d) => !ignoreDirectory(options, d.basename, d.fullPath),
lstat: true
});
// @ts-ignore
Expand Down
4 changes: 3 additions & 1 deletion src/Options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@ export default interface Options {
output: string,
type?: string,
recurse: boolean,
tsTypes: boolean
tsTypes: boolean,
"exclude-file": string[],
"exclude-regex"?: RegExp
}
19 changes: 19 additions & 0 deletions src/astgen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ async function main(argv: string[]) {
.option("src", {
alias: "i",
default: ".",
coerce: (arg: any): string => {
return path.resolve(arg.toString())
},
description: "Source directory",
})
.option("output", {
Expand All @@ -35,6 +38,22 @@ async function main(argv: string[]) {
type: "boolean",
description: "Generate type mappings using the Typescript Compiler API",
})
.option("exclude-file", {
default: [],
type: "string",
array: true,
description: "Exclude this file. Can be specified multiple times. Default is empty."
})
.option("exclude-regex", {
coerce: (arg: any): RegExp | undefined => {
try {
return new RegExp(arg.toString(), "i")
} catch (err) {
return undefined;
}
},
description: "Exclude files matching this regex (matches the absolute path)."
})
.version()
.help("h").parseSync();

Expand Down
16 changes: 8 additions & 8 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ function createTsc(srcFiles: string[]): TscUtils.TscResult | undefined {
*/
async function createJSAst(options: Options) {
try {
const srcFiles: string[] = await FileUtils.filesWithExtensions(options.src, Defaults.JS_EXTENSIONS);
const srcFiles: string[] = await FileUtils.filesWithExtensions(options, Defaults.JS_EXTENSIONS);
let ts: TscUtils.TscResult | undefined;
if (options.tsTypes) {
ts = createTsc(srcFiles);
Expand Down Expand Up @@ -95,7 +95,7 @@ async function createJSAst(options: Options) {
* Generate AST for .vue files
*/
async function createVueAst(options: Options) {
const srcFiles: string[] = await FileUtils.filesWithExtensions(options.src, [".vue"]);
const srcFiles: string[] = await FileUtils.filesWithExtensions(options, [".vue"]);
for (const file of srcFiles) {
try {
const ast = toVueAst(file);
Expand Down Expand Up @@ -138,20 +138,20 @@ function writeTypesFile(file: string, seenTypes: Map<number, string>, options: O
}

async function createXAst(options: Options) {
const src_dir = options.src;
const srcDir = options.src;
try {
fs.accessSync(src_dir, fs.constants.R_OK);
fs.accessSync(srcDir, fs.constants.R_OK);
} catch (err) {
console.error(src_dir, "is invalid");
console.error(srcDir, "is invalid");
process.exit(1);
}
if (
fs.existsSync(path.join(src_dir, "package.json")) ||
fs.existsSync(path.join(src_dir, "rush.json"))
fs.existsSync(path.join(srcDir, "package.json")) ||
fs.existsSync(path.join(srcDir, "rush.json"))
) {
return await createJSAst(options);
}
console.error(src_dir, "unknown project type");
console.error(srcDir, "unknown project type");
process.exit(1);
}

Expand Down
110 changes: 109 additions & 1 deletion test/astgen.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ describe('astgen basic functionality', () => {
type: "js",
output: path.join(tmpDir, "ast_out"),
recurse: true,
tsTypes: true
tsTypes: true,
"exclude-file": []
});
const resultAst = fs.readFileSync(path.join(tmpDir, "ast_out", "main.js.json")).toString();
expect(resultAst).toContain("\"fullName\":\"" + testFile.replaceAll("\\", "\\\\") + "\"");
Expand All @@ -24,4 +25,111 @@ describe('astgen basic functionality', () => {

fs.rmSync(tmpDir, {recursive: true});
});

it('should exclude files by relative file path correctly', async () => {
const tmpDir: string = fs.mkdtempSync(path.join(os.tmpdir(), "astgen-tests"));
const testFile = path.join(tmpDir, "main.js");
fs.writeFileSync(testFile, "console.log(\"Hello, world!\");");
await start({
src: tmpDir,
type: "js",
output: path.join(tmpDir, "ast_out"),
recurse: true,
tsTypes: false,
"exclude-file": ["main.js"]
});
expect(fs.existsSync(path.join(tmpDir, "ast_out", "main.js.json"))).toBeFalsy()

fs.rmSync(tmpDir, {recursive: true});
});

it('should exclude files by absolute file path correctly', async () => {
const tmpDir: string = fs.mkdtempSync(path.join(os.tmpdir(), "astgen-tests"));
const testFile = path.join(tmpDir, "main.js");
fs.writeFileSync(testFile, "console.log(\"Hello, world!\");");
await start({
src: tmpDir,
type: "js",
output: path.join(tmpDir, "ast_out"),
recurse: true,
tsTypes: false,
"exclude-file": [testFile]
});
expect(fs.existsSync(path.join(tmpDir, "ast_out", "main.js.json"))).toBeFalsy()

fs.rmSync(tmpDir, {recursive: true});
});

it('should exclude files by relative file path with dir correctly', async () => {
const tmpDir: string = fs.mkdtempSync(path.join(os.tmpdir(), "astgen-tests"));
const testFile = path.join(tmpDir, "src", "main.js");
fs.mkdirSync(path.join(tmpDir, "src"))
fs.writeFileSync(testFile, "console.log(\"Hello, world!\");");
await start({
src: tmpDir,
type: "js",
output: path.join(tmpDir, "ast_out"),
recurse: true,
tsTypes: false,
"exclude-file": [path.join("src", "main.js")]
});
expect(fs.existsSync(path.join(tmpDir, "ast_out", "src", "main.js.json"))).toBeFalsy()

fs.rmSync(tmpDir, {recursive: true});
});

it('should exclude files by relative dir path correctly', async () => {
const tmpDir: string = fs.mkdtempSync(path.join(os.tmpdir(), "astgen-tests"));
const testFile = path.join(tmpDir, "src", "main.js");
fs.mkdirSync(path.join(tmpDir, "src"))
fs.writeFileSync(testFile, "console.log(\"Hello, world!\");");
await start({
src: tmpDir,
type: "js",
output: path.join(tmpDir, "ast_out"),
recurse: true,
tsTypes: false,
"exclude-file": ["src"]
});
expect(fs.existsSync(path.join(tmpDir, "ast_out", "src", "main.js.json"))).toBeFalsy()

fs.rmSync(tmpDir, {recursive: true});
});

it('should exclude files by absolute dir path correctly', async () => {
const tmpDir: string = fs.mkdtempSync(path.join(os.tmpdir(), "astgen-tests"));
const testFile = path.join(tmpDir, "src", "main.js");
fs.mkdirSync(path.join(tmpDir, "src"))
fs.writeFileSync(testFile, "console.log(\"Hello, world!\");");
await start({
src: tmpDir,
type: "js",
output: path.join(tmpDir, "ast_out"),
recurse: true,
tsTypes: false,
"exclude-file": [path.join(tmpDir, "src")]
});
expect(fs.existsSync(path.join(tmpDir, "ast_out", "main.js.json"))).toBeFalsy()

fs.rmSync(tmpDir, {recursive: true});
});

it('should exclude files by regex correctly', async () => {
const tmpDir: string = fs.mkdtempSync(path.join(os.tmpdir(), "astgen-tests"));
const testFile = path.join(tmpDir, "main.js");
fs.writeFileSync(testFile, "console.log(\"Hello, world!\");");
await start({
src: tmpDir,
type: "js",
output: path.join(tmpDir, "ast_out"),
recurse: true,
tsTypes: false,
"exclude-file": [],
"exclude-regex": new RegExp(".*main.*", "i")
});
expect(fs.existsSync(path.join(tmpDir, "ast_out", "main.js.json"))).toBeFalsy()

fs.rmSync(tmpDir, {recursive: true});
});

});

0 comments on commit af964b8

Please sign in to comment.