-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: runASTAnalysis functions to use class AstAnalyser (#216)
* refactor: create and use AstAnalyser class to handle ast analysis * refactor: remove useless JSDoc * fix: ESTree type from meriyah * fix: add JSDoc again * fix: optimize regular expression by removing non-capturing group * fix: revert regex to the original pattern * fix: declare class AstAnalyser instead of interface * fix: replace Parser type by SourceParser type * fix: parsers should return body directly
- Loading branch information
1 parent
83aa3d5
commit e59a1a5
Showing
12 changed files
with
472 additions
and
352 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,95 +1,39 @@ | ||
// Import Node.js Dependencies | ||
import fs from "fs/promises"; | ||
import path from "path"; | ||
|
||
// Import Third-party Dependencies | ||
import { walk } from "estree-walker"; | ||
import isMinified from "is-minified-code"; | ||
|
||
// Import Internal Dependencies | ||
import { SourceFile } from "./src/SourceFile.js"; | ||
import { warnings } from "./src/warnings.js"; | ||
import { isOneLineExpressionExport } from "./src/utils/index.js"; | ||
import { JsSourceParser } from "./src/JsSourceParser.js"; | ||
import { AstAnalyser } from "./src/AstAnalyser.js"; | ||
|
||
export function runASTAnalysis( | ||
function runASTAnalysis( | ||
str, | ||
options = Object.create(null) | ||
) { | ||
const { | ||
module = true, | ||
isMinified = false, | ||
removeHTMLComments = false | ||
customParser = new JsSourceParser(), | ||
...opts | ||
} = options; | ||
|
||
const parser = new JsSourceParser(str, { removeHTMLComments }); | ||
const body = parser.parseScript({ | ||
isEcmaScriptModule: Boolean(module) | ||
}); | ||
|
||
const source = new SourceFile(parser.raw); | ||
|
||
// we walk each AST Nodes, this is a purely synchronous I/O | ||
walk(body, { | ||
enter(node) { | ||
// Skip the root of the AST. | ||
if (Array.isArray(node)) { | ||
return; | ||
} | ||
const analyser = new AstAnalyser(customParser); | ||
|
||
const action = source.walk(node); | ||
if (action === "skip") { | ||
this.skip(); | ||
} | ||
} | ||
}); | ||
|
||
return { | ||
...source.getResult(isMinified), | ||
dependencies: source.dependencies, | ||
isOneLineRequire: isOneLineExpressionExport(body) | ||
}; | ||
return analyser.analyse(str, opts); | ||
} | ||
|
||
export async function runASTAnalysisOnFile( | ||
async function runASTAnalysisOnFile( | ||
pathToFile, | ||
options = {} | ||
) { | ||
try { | ||
const { | ||
packageName = null, | ||
module = true, | ||
removeHTMLComments = false | ||
} = options; | ||
|
||
const str = await fs.readFile(pathToFile, "utf-8"); | ||
const filePathString = pathToFile instanceof URL ? pathToFile.href : pathToFile; | ||
const { | ||
customParser = new JsSourceParser(), | ||
...opts | ||
} = options; | ||
|
||
const isMin = filePathString.includes(".min") || isMinified(str); | ||
const data = runASTAnalysis(str, { | ||
isMinified: isMin, | ||
module: path.extname(filePathString) === ".mjs" ? true : module, | ||
removeHTMLComments | ||
}); | ||
if (packageName !== null) { | ||
data.dependencies.delete(packageName); | ||
} | ||
const analyser = new AstAnalyser(customParser); | ||
|
||
return { | ||
ok: true, | ||
dependencies: data.dependencies, | ||
warnings: data.warnings, | ||
isMinified: !data.isOneLineRequire && isMin | ||
}; | ||
} | ||
catch (error) { | ||
return { | ||
ok: false, | ||
warnings: [ | ||
{ kind: "parsing-error", value: error.message, location: [[0, 0], [0, 0]] } | ||
] | ||
}; | ||
} | ||
return analyser.analyseFile(pathToFile, opts); | ||
} | ||
|
||
export { warnings }; | ||
export { | ||
warnings, | ||
AstAnalyser, | ||
runASTAnalysis, | ||
runASTAnalysisOnFile | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
// Import Node.js Dependencies | ||
import fs from "node:fs/promises"; | ||
import path from "node:path"; | ||
|
||
// Import Third-party Dependencies | ||
import { walk } from "estree-walker"; | ||
import isMinified from "is-minified-code"; | ||
|
||
// Import Internal Dependencies | ||
import { SourceFile } from "./SourceFile.js"; | ||
import { isOneLineExpressionExport } from "./utils/index.js"; | ||
|
||
export class AstAnalyser { | ||
/** | ||
* @constructor | ||
* @param { SourceParser } parser | ||
*/ | ||
constructor(parser) { | ||
this.parser = parser; | ||
} | ||
|
||
analyse(str, options = Object.create(null)) { | ||
const { | ||
isMinified = false, | ||
module = true, | ||
removeHTMLComments = false | ||
} = options; | ||
|
||
const body = this.parser.parse(this.prepareSource(str, { removeHTMLComments }), { | ||
isEcmaScriptModule: Boolean(module) | ||
}); | ||
|
||
const source = new SourceFile(str); | ||
|
||
// we walk each AST Nodes, this is a purely synchronous I/O | ||
walk(body, { | ||
enter(node) { | ||
// Skip the root of the AST. | ||
if (Array.isArray(node)) { | ||
return; | ||
} | ||
|
||
const action = source.walk(node); | ||
if (action === "skip") { | ||
this.skip(); | ||
} | ||
} | ||
}); | ||
|
||
return { | ||
...source.getResult(isMinified), | ||
dependencies: source.dependencies, | ||
isOneLineRequire: isOneLineExpressionExport(body) | ||
}; | ||
} | ||
|
||
async analyseFile( | ||
pathToFile, | ||
options = {} | ||
) { | ||
try { | ||
const { | ||
packageName = null, | ||
module = true, | ||
removeHTMLComments = false | ||
} = options; | ||
|
||
const str = await fs.readFile(pathToFile, "utf-8"); | ||
const filePathString = pathToFile instanceof URL ? pathToFile.href : pathToFile; | ||
|
||
const isMin = filePathString.includes(".min") || isMinified(str); | ||
const data = this.analyse(str, { | ||
isMinified: isMin, | ||
module: path.extname(filePathString) === ".mjs" ? true : module, | ||
removeHTMLComments | ||
}); | ||
|
||
if (packageName !== null) { | ||
data.dependencies.delete(packageName); | ||
} | ||
|
||
return { | ||
ok: true, | ||
dependencies: data.dependencies, | ||
warnings: data.warnings, | ||
isMinified: !data.isOneLineRequire && isMin | ||
}; | ||
} | ||
catch (error) { | ||
return { | ||
ok: false, | ||
warnings: [ | ||
{ kind: "parsing-error", value: error.message, location: [[0, 0], [0, 0]] } | ||
] | ||
}; | ||
} | ||
} | ||
|
||
/** | ||
* @param {!string} source | ||
* @param {object} options | ||
* @param {boolean} [options.removeHTMLComments=false] | ||
*/ | ||
prepareSource(source, options = {}) { | ||
if (typeof source !== "string") { | ||
throw new TypeError("source must be a string"); | ||
} | ||
const { removeHTMLComments = false } = options; | ||
|
||
/** | ||
* if the file start with a shebang then we remove it because meriyah.parseScript fail to parse it. | ||
* @example | ||
* #!/usr/bin/env node | ||
*/ | ||
const rawNoShebang = source.startsWith("#") ? | ||
source.slice(source.indexOf("\n") + 1) : source; | ||
|
||
return removeHTMLComments ? | ||
this.#removeHTMLComment(rawNoShebang) : rawNoShebang; | ||
} | ||
|
||
/** | ||
* @param {!string} str | ||
* @returns {string} | ||
*/ | ||
#removeHTMLComment(str) { | ||
return str.replaceAll(/<!--[\s\S]*?(?:-->)/g, ""); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.