Skip to content

Commit adddcc9

Browse files
Added readable check to src dir (#48)
Also: updated @yao-pkg/pkg
1 parent c42171d commit adddcc9

File tree

10 files changed

+287
-177
lines changed

10 files changed

+287
-177
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@joernio/astgen",
3-
"version": "3.35.0",
3+
"version": "3.36.0",
44
"description": "Generate JS/TS AST in json format with Babel",
55
"exports": "./index.js",
66
"keywords": [
@@ -41,7 +41,7 @@
4141
"@types/n-readlines": "^1.0.6",
4242
"@types/node": "^18.11.9",
4343
"@types/yargs": "^17.0.33",
44-
"@yao-pkg/pkg": "^6.5.1",
44+
"@yao-pkg/pkg": "^6.9.0",
4545
"jest": "^30.0.4",
4646
"ts-jest": "^29.3.4"
4747
}

src/AstGenerator.ts

Lines changed: 43 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ import * as fs from "node:fs"
2222
*/
2323
function TWithTry<T>(errMessage: string, arg: string, f: () => O.Option<T>): O.Option<T> {
2424
try {
25-
return f();
25+
return f()
2626
} catch (err) {
2727
if (err instanceof Error) {
28-
console.warn(errMessage, arg, ":", err.message);
28+
console.warn(errMessage, arg, ":", err.message)
2929
}
30-
return O.none();
30+
return O.none()
3131
}
3232
}
3333

@@ -42,8 +42,8 @@ function TWithTry<T>(errMessage: string, arg: string, f: () => O.Option<T>): O.O
4242
*/
4343
function VoidWithTry(errMessage: string, arg: string, f: () => void): void {
4444
TWithTry(errMessage, arg, () => {
45-
f();
46-
return O.none();
45+
f()
46+
return O.none()
4747
})
4848
}
4949

@@ -58,7 +58,7 @@ function VoidWithTry(errMessage: string, arg: string, f: () => void): void {
5858
* @see codeToJsAst - The underlying function used for parsing code strings
5959
*/
6060
function fileToJsAst(file: string): babelParser.ParseResult {
61-
return codeToJsAst(fs.readFileSync(file, "utf-8"));
61+
return codeToJsAst(fs.readFileSync(file, "utf-8"))
6262
}
6363

6464
/**
@@ -76,9 +76,9 @@ function fileToJsAst(file: string): babelParser.ParseResult {
7676
*/
7777
function codeToJsAst(code: string): babelParser.ParseResult {
7878
try {
79-
return babelParser.parse(code, Defaults.BABEL_PARSER_OPTIONS);
79+
return babelParser.parse(code, Defaults.BABEL_PARSER_OPTIONS)
8080
} catch {
81-
return babelParser.parse(code, Defaults.SAFE_BABEL_PARSER_OPTIONS);
81+
return babelParser.parse(code, Defaults.SAFE_BABEL_PARSER_OPTIONS)
8282
}
8383
}
8484

@@ -96,9 +96,9 @@ function codeToJsAst(code: string): babelParser.ParseResult {
9696
* @see codeToJsAst - The underlying function used for parsing the extracted code
9797
*/
9898
function toVueAst(file: string): babelParser.ParseResult {
99-
const code = fs.readFileSync(file, "utf-8");
99+
const code = fs.readFileSync(file, "utf-8")
100100
const cleanedCode = VueCodeCleaner.cleanVueCode(code)
101-
return codeToJsAst(cleanedCode);
101+
return codeToJsAst(cleanedCode)
102102
}
103103

104104
/**
@@ -115,9 +115,9 @@ function toVueAst(file: string): babelParser.ParseResult {
115115
* @see TscUtils - The utility class used for TypeScript type extraction
116116
*/
117117
function buildTscUtils(files: string[], options: Options): O.Option<TscUtils> {
118-
if (!options.tsTypes || files.length === 0) return O.none();
118+
if (!options.tsTypes || files.length === 0) return O.none()
119119
return TWithTry("Retrieving types", "", () => {
120-
return O.some(new TscUtils(files));
120+
return O.some(new TscUtils(files))
121121
})
122122
}
123123

@@ -136,12 +136,12 @@ function buildTscUtils(files: string[], options: Options): O.Option<TscUtils> {
136136
*/
137137
async function createJSAst(options: Options): Promise<void> {
138138
try {
139-
const srcFiles: string[] = await FileUtils.filesWithExtensions(options, Defaults.JS_EXTENSIONS);
140-
const tscUtils: O.Option<TscUtils> = buildTscUtils(srcFiles, options);
139+
const srcFiles: string[] = await FileUtils.filesWithExtensions(options, Defaults.JS_EXTENSIONS)
140+
const tscUtils: O.Option<TscUtils> = buildTscUtils(srcFiles, options)
141141
for (const file of srcFiles) {
142142
VoidWithTry("Parsing", file, () => {
143-
const ast: babelParser.ParseResult = fileToJsAst(file);
144-
writeAstFile(file, ast, options);
143+
const ast: babelParser.ParseResult = fileToJsAst(file)
144+
writeAstFile(file, ast, options)
145145
VoidWithTry("Retrieving types", file, () => {
146146
pipe(
147147
tscUtils,
@@ -153,7 +153,7 @@ async function createJSAst(options: Options): Promise<void> {
153153
})
154154
}
155155
} catch (err) {
156-
console.error(err);
156+
console.error(err)
157157
}
158158
}
159159

@@ -168,10 +168,10 @@ async function createJSAst(options: Options): Promise<void> {
168168
* @returns A Promise that resolves when all Vue files have been processed.
169169
*/
170170
async function createVueAst(options: Options): Promise<void> {
171-
const srcFiles: string[] = await FileUtils.filesWithExtensions(options, [".vue"]);
171+
const srcFiles: string[] = await FileUtils.filesWithExtensions(options, [".vue"])
172172
for (const file of srcFiles) {
173173
VoidWithTry("", file, () => {
174-
writeAstFile(file, toVueAst(file), options);
174+
writeAstFile(file, toVueAst(file), options)
175175
})
176176
}
177177
}
@@ -189,15 +189,15 @@ async function createVueAst(options: Options): Promise<void> {
189189
*/
190190
function writeAstFile(file: string, ast: babelParser.ParseResult, options: Options): void {
191191
const relativePath: string = path.relative(options.src, file)
192-
const outAstFile: string = path.join(options.output, relativePath + ".json");
192+
const outAstFile: string = path.join(options.output, relativePath + ".json")
193193
const data = {
194194
fullName: file,
195195
relativeName: relativePath,
196196
ast: ast,
197-
};
198-
fs.mkdirSync(path.dirname(outAstFile), {recursive: true});
199-
fs.writeFileSync(outAstFile, JsonUtils.stringifyCircular(data));
200-
console.log("Converted AST for", relativePath, "to", outAstFile);
197+
}
198+
fs.mkdirSync(path.dirname(outAstFile), {recursive: true})
199+
fs.writeFileSync(outAstFile, JsonUtils.stringifyCircular(data))
200+
console.log("Converted AST for", relativePath, "to", outAstFile)
201201
}
202202

203203
/**
@@ -212,10 +212,10 @@ function writeAstFile(file: string, ast: babelParser.ParseResult, options: Optio
212212
*/
213213
function writeTypesFile(file: string, seenTypes: TypeMap, options: Options): void {
214214
const relativePath: string = path.relative(options.src, file)
215-
const outTypeFile: string = path.join(options.output, relativePath + ".typemap");
216-
fs.mkdirSync(path.dirname(outTypeFile), {recursive: true});
217-
fs.writeFileSync(outTypeFile, JsonUtils.stringify(Object.fromEntries(seenTypes)));
218-
console.log("Converted types for", relativePath, "to", outTypeFile);
215+
const outTypeFile: string = path.join(options.output, relativePath + ".typemap")
216+
fs.mkdirSync(path.dirname(outTypeFile), {recursive: true})
217+
fs.writeFileSync(outTypeFile, JsonUtils.stringify(Object.fromEntries(seenTypes)))
218+
console.log("Converted types for", relativePath, "to", outTypeFile)
219219
}
220220

221221
/**
@@ -229,21 +229,15 @@ function writeTypesFile(file: string, seenTypes: TypeMap, options: Options): voi
229229
* @returns A Promise that resolves when AST generation is complete or the process exits on error.
230230
*/
231231
async function createXAst(options: Options): Promise<void> {
232-
const srcDir: string = options.src;
233-
try {
234-
fs.accessSync(srcDir, fs.constants.R_OK);
235-
} catch (err) {
236-
console.error(srcDir, "is invalid");
237-
process.exit(1);
238-
}
232+
const srcDir: string = options.src
239233
if (
240-
fs.existsSync(path.join(srcDir, "package.json")) ||
241-
fs.existsSync(path.join(srcDir, "rush.json"))
234+
FileUtils.fileExistsAndIsReadable(path.join(srcDir, "package.json")) ||
235+
FileUtils.fileExistsAndIsReadable(path.join(srcDir, "rush.json"))
242236
) {
243-
return await createJSAst(options);
237+
return await createJSAst(options)
244238
}
245-
console.error(srcDir, "unknown project type");
246-
process.exit(1);
239+
console.error("Unknown project type:", srcDir)
240+
process.exit(1)
247241
}
248242

249243
/**
@@ -259,17 +253,23 @@ async function createXAst(options: Options): Promise<void> {
259253
* @returns A Promise that resolves when the AST generation process is complete.
260254
*/
261255
export default async function start(options: Options): Promise<void> {
256+
const srcDir = options.src
257+
if (!FileUtils.fileExistsAndIsReadable(srcDir)) {
258+
console.error("Source directory does not exist or is not readable:", srcDir)
259+
process.exit(1)
260+
}
261+
262262
const type: string = (options.type || "").toLowerCase()
263263
switch (type) {
264264
case "nodejs":
265265
case "js":
266266
case "javascript":
267267
case "typescript":
268268
case "ts":
269-
return await createJSAst(options);
269+
return await createJSAst(options)
270270
case "vue":
271-
return await createVueAst(options);
271+
return await createVueAst(options)
272272
default:
273-
return await createXAst(options);
273+
return await createXAst(options)
274274
}
275275
}

src/Defaults.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import babelParser from "@babel/parser";
2-
import tsc from "typescript";
1+
import babelParser from "@babel/parser"
2+
import tsc from "typescript"
33

44
export const JS_EXTENSIONS: string[] = [
55
".js",
@@ -31,12 +31,12 @@ export const IGNORE_DIRS: string[] = [
3131
"www",
3232
"dist",
3333
"build",
34-
];
34+
]
3535

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

39-
export const MAX_LOC_IN_FILE: number = 50000;
39+
export const MAX_LOC_IN_FILE: number = 50000
4040

4141
export const BABEL_PARSER_OPTIONS: babelParser.ParserOptions = {
4242
sourceType: "unambiguous",
@@ -58,7 +58,7 @@ export const BABEL_PARSER_OPTIONS: babelParser.ParserOptions = {
5858
"jsx",
5959
"typescript",
6060
],
61-
};
61+
}
6262

6363
export const SAFE_BABEL_PARSER_OPTIONS: babelParser.ParserOptions = {
6464
sourceType: "module",
@@ -76,7 +76,7 @@ export const SAFE_BABEL_PARSER_OPTIONS: babelParser.ParserOptions = {
7676
"dynamicImport",
7777
"typescript",
7878
],
79-
};
79+
}
8080

8181
export const DEFAULT_TSC_OPTIONS: tsc.CompilerOptions = {
8282
target: tsc.ScriptTarget.ES2020,

src/FileUtils.ts

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
import Options from "./Options";
2-
import * as Defaults from "./Defaults";
1+
import Options from "./Options"
2+
import * as Defaults from "./Defaults"
33

4-
import {readdirpPromise} from 'readdirp';
5-
import * as fs from "node:fs";
6-
import nReadlines from "n-readlines";
4+
import {readdirpPromise} from 'readdirp'
5+
import * as fs from "node:fs"
6+
import nReadlines from "n-readlines"
77
import * as path from "node:path"
88

99
function countFileLines(filePath: string): number {
10-
const broadbandLines = new nReadlines(filePath);
11-
let lineNumber = 1;
10+
const broadbandLines = new nReadlines(filePath)
11+
let lineNumber = 1
1212
while (broadbandLines.next()) {
13-
lineNumber++;
13+
lineNumber++
1414
}
1515
return lineNumber
1616
}
@@ -43,18 +43,18 @@ function ignoreDirectory(options: Options, dirName: string, fullPath: string): b
4343

4444
function isEmscripten(fileWithDir: string): boolean {
4545
if (fs.readFileSync(fileWithDir, "utf-8").toString().includes("// EMSCRIPTEN_START_ASM")) {
46-
console.warn("Parsing", fileWithDir, ":", "File skipped as it contains EMSCRIPTEN code");
47-
return true;
46+
console.warn("Parsing", fileWithDir, ":", "File skipped as it contains EMSCRIPTEN code")
47+
return true
4848
}
49-
return false;
49+
return false
5050
}
5151

5252
function isTooLarge(fileWithDir: string): boolean {
5353
if (countFileLines(fileWithDir) > Defaults.MAX_LOC_IN_FILE) {
54-
console.warn(fileWithDir, "more than", Defaults.MAX_LOC_IN_FILE, "lines of code");
55-
return true;
54+
console.warn(fileWithDir, "more than", Defaults.MAX_LOC_IN_FILE, "lines of code")
55+
return true
5656
}
57-
return false;
57+
return false
5858
}
5959

6060
function ignoreFile(options: Options, fileName: string, fullPath: string, extensions: string[]): boolean {
@@ -82,7 +82,22 @@ export async function filesWithExtensions(options: Options, extensions: string[]
8282
fileFilter: (f) => !ignoreFile(options, f.basename, f.fullPath, extensions),
8383
directoryFilter: (d) => !ignoreDirectory(options, d.basename, d.fullPath),
8484
lstat: true
85-
});
85+
})
8686
// @ts-ignore
87-
return files.map(file => file.fullPath);
87+
return files.map(file => file.fullPath)
8888
}
89+
90+
/**
91+
* Checks if the folder or file at the given path exists and is readable.
92+
*
93+
* @param path - The path to the folder or file to check.
94+
* @returns True if the folder or file exists and is readable; false otherwise.
95+
*/
96+
export function fileExistsAndIsReadable(path: string): boolean {
97+
try {
98+
fs.accessSync(path, fs.constants.R_OK)
99+
return true
100+
} catch (err) {
101+
return false
102+
}
103+
}

src/JsonUtils.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@
44
* @returns {(key: any, value: any) => any} A replacer function for JSON.stringify.
55
*/
66
const getCircularReplacer = () => {
7-
const seen = new WeakSet();
7+
const seen = new WeakSet()
88
return (_: any, value: any): any => {
99
if (typeof value === "object" && value !== null) {
1010
if (seen.has(value)) {
11-
return;
11+
return
1212
}
13-
seen.add(value);
13+
seen.add(value)
1414
}
15-
return value;
16-
};
17-
};
15+
return value
16+
}
17+
}
1818

1919
/**
2020
* Safely serializes objects with potential circular references to a JSON string.

0 commit comments

Comments
 (0)