@@ -17,11 +17,17 @@ import {
1717 SourceFile ,
1818 type SourceFlags
1919} from "./SourceFile.js" ;
20- import { isOneLineExpressionExport } from "./utils/index.js" ;
2120import { JsSourceParser , type SourceParser } from "./JsSourceParser.js" ;
2221import { ProbeRunner , type Probe } from "./ProbeRunner.js" ;
2322import { walkEnter } from "./walker/index.js" ;
2423import * as trojan from "./obfuscators/trojan-source.js" ;
24+ import {
25+ isOneLineExpressionExport
26+ } from "./utils/index.js" ;
27+ import {
28+ PipelineRunner ,
29+ type Pipeline
30+ } from "./pipelines/index.js" ;
2531
2632export interface Dependency {
2733 unsafe : boolean ;
@@ -85,23 +91,27 @@ export interface AstAnalyserOptions {
8591 * @default false
8692 */
8793 optionalWarnings ?: boolean | Iterable < OptionalWarningName > ;
94+ pipelines ?: Pipeline [ ] ;
8895}
8996
9097export interface PrepareSourceOptions {
9198 removeHTMLComments ?: boolean ;
9299}
93100
94101export class AstAnalyser {
102+ #pipelineRunner: PipelineRunner ;
95103 parser : SourceParser ;
96104 probes : Probe [ ] ;
97105
98106 constructor ( options : AstAnalyserOptions = { } ) {
99107 const {
100108 customProbes = [ ] ,
101109 optionalWarnings = false ,
102- skipDefaultProbes = false
110+ skipDefaultProbes = false ,
111+ pipelines = [ ]
103112 } = options ;
104113
114+ this . #pipelineRunner = new PipelineRunner ( pipelines ) ;
105115 this . parser = options . customParser ?? new JsSourceParser ( ) ;
106116
107117 let probes = ProbeRunner . Defaults ;
@@ -144,15 +154,15 @@ export class AstAnalyser {
144154 const body = this . parser . parse ( this . prepareSource ( str , { removeHTMLComments } ) , {
145155 isEcmaScriptModule : Boolean ( module )
146156 } ) ;
157+
147158 const source = new SourceFile ( ) ;
148159 if ( trojan . verify ( str ) ) {
149160 source . warnings . push (
150161 generateWarning ( "obfuscated-code" , { value : "trojan-source" } )
151162 ) ;
152163 }
153164
154- const runner = new ProbeRunner ( source , this . probes ) ;
155-
165+ const probeRunner = new ProbeRunner ( source , this . probes ) ;
156166 if ( initialize ) {
157167 if ( typeof initialize !== "function" ) {
158168 throw new TypeError ( "options.initialize must be a function" ) ;
@@ -161,14 +171,15 @@ export class AstAnalyser {
161171 }
162172
163173 // we walk each AST Nodes, this is a purely synchronous I/O
164- walkEnter ( body , function walk ( node ) {
174+ const reducedBody = this . #pipelineRunner. reduce ( body ) ;
175+ walkEnter ( reducedBody , function walk ( node ) {
165176 // Skip the root of the AST.
166177 if ( Array . isArray ( node ) ) {
167178 return ;
168179 }
169180
170181 source . walk ( node ) ;
171- const action = runner . walk ( node ) ;
182+ const action = probeRunner . walk ( node ) ;
172183 if ( action === "skip" ) {
173184 this . skip ( ) ;
174185 }
@@ -180,7 +191,7 @@ export class AstAnalyser {
180191 }
181192 finalize ( source ) ;
182193 }
183- runner . finalize ( ) ;
194+ probeRunner . finalize ( ) ;
184195
185196 // Add oneline-require flag if this is a one-line require expression
186197 if ( isOneLineExpressionExport ( body ) ) {
0 commit comments