From 98f190ca2d0def3bb03f8a5f9adc59601ad56ce1 Mon Sep 17 00:00:00 2001 From: GENTILHOMME Thomas Date: Sat, 15 Aug 2026 20:49:14 +0200 Subject: [PATCH] feat(scanner): customize AstAnalyserOptions for main APIs (from, workingDir, verify) --- .changeset/curvy-dragons-spend.md | 5 ++++ workspaces/scanner/README.md | 28 ++++++++++++++++++- workspaces/scanner/docs/from.md | 9 ++++++ workspaces/scanner/docs/verify.md | 7 ++++- workspaces/scanner/docs/workingDir.md | 9 ++++++ .../scanner/src/class/TarballScanner.class.ts | 15 ++++++++-- workspaces/scanner/src/depWalker.ts | 6 ++-- workspaces/scanner/src/index.ts | 20 +++++++++++-- workspaces/scanner/src/types.ts | 16 ++++++++++- 9 files changed, 104 insertions(+), 11 deletions(-) create mode 100644 .changeset/curvy-dragons-spend.md diff --git a/.changeset/curvy-dragons-spend.md b/.changeset/curvy-dragons-spend.md new file mode 100644 index 00000000..400a4007 --- /dev/null +++ b/.changeset/curvy-dragons-spend.md @@ -0,0 +1,5 @@ +--- +"@nodesecure/scanner": minor +--- + +Implement AstAnalyserOptions for main scanner API (from, workingDir and verify) diff --git a/workspaces/scanner/README.md b/workspaces/scanner/README.md index 667110ef..8520ba4a 100644 --- a/workspaces/scanner/README.md +++ b/workspaces/scanner/README.md @@ -58,7 +58,8 @@ function from( logger?: Scanner.Logger ): Promise; function verify( - spec?: string + spec?: string, + options?: VerifyOptions ): Promise; ``` @@ -89,6 +90,10 @@ type FromOptions = Omit & { ) => Promise; }; +interface VerifyOptions { + astAnalyserOptions?: AstAnalyserOptions; +} + interface Options { /** * Specifies the maximum depth to traverse for each root dependency. @@ -157,6 +162,27 @@ interface Options { * @default true for cwd() API */ readonly scanRootNode?: boolean; + + /** + * Enable verbose mode + * + * @default false + */ + isVerbose?: boolean; + + /** + * Enable worker threads for parallel tarball scanning. + * - `true` uses the default worker count (4) + * - `number` sets an explicit worker count + * + * @default false + */ + readonly workers?: boolean | number; + + /** + * Custom options for JS-X-Ray + */ + readonly astAnalyserOptions?: AstAnalyserOptions; } ``` diff --git a/workspaces/scanner/docs/from.md b/workspaces/scanner/docs/from.md index 4b003b22..40c1acf3 100644 --- a/workspaces/scanner/docs/from.md +++ b/workspaces/scanner/docs/from.md @@ -112,6 +112,15 @@ export interface Options { * @default false */ readonly workers?: boolean | number; + + /** + * Custom options for the underhood JS-X-Ray instance + * when scanning tarballs or local directories + * + * @note + * Do not support `collectable` option + */ + readonly astAnalyserOptions?: AstAnalyserOptionsNoCollectable; } ``` diff --git a/workspaces/scanner/docs/verify.md b/workspaces/scanner/docs/verify.md index c430d4ed..602c0823 100644 --- a/workspaces/scanner/docs/verify.md +++ b/workspaces/scanner/docs/verify.md @@ -12,8 +12,13 @@ console.log(result); ## Signature ```ts +export interface VerifyOptions { + astAnalyserOptions?: AstAnalyserOptions; +} + function verify( - spec?: string + spec?: string, + options?: VerifyOptions ): Promise ``` diff --git a/workspaces/scanner/docs/workingDir.md b/workspaces/scanner/docs/workingDir.md index da223466..574f831e 100644 --- a/workspaces/scanner/docs/workingDir.md +++ b/workspaces/scanner/docs/workingDir.md @@ -129,6 +129,15 @@ export interface Options { * @default false */ readonly workers?: boolean | number; + + /** + * Custom options for the underhood JS-X-Ray instance + * when scanning tarballs or local directories + * + * @note + * Do not support `collectable` option + */ + readonly astAnalyserOptions?: AstAnalyserOptionsNoCollectable; } ``` diff --git a/workspaces/scanner/src/class/TarballScanner.class.ts b/workspaces/scanner/src/class/TarballScanner.class.ts index a0b49650..7b2a2360 100644 --- a/workspaces/scanner/src/class/TarballScanner.class.ts +++ b/workspaces/scanner/src/class/TarballScanner.class.ts @@ -17,6 +17,9 @@ import { ManifestManager } from "@nodesecure/mama"; import { StatsCollector } from "./StatsCollector.class.ts"; import { TempDirectory } from "./TempDirectory.class.ts"; import { Logger, ScannerLoggerEvents } from "./logger.class.ts"; +import type { + AstAnalyserOptionsNoCollectable +} from "../types.ts"; type CollectableMetadata = { spec?: string; }; @@ -37,6 +40,7 @@ export interface TarballScannerOptions { maxConcurrency: number; logger: Logger; workers?: boolean | number; + astAnalyserOptions?: AstAnalyserOptionsNoCollectable; } export class TarballScanner { @@ -48,6 +52,7 @@ export class TarballScanner { #collectableTypes: string[]; #workerPool: NpmTarballWorkerPool | null; #logger: Logger; + #astAnalyserOptions: AstAnalyserOptionsNoCollectable; constructor( options: TarballScannerOptions @@ -59,7 +64,8 @@ export class TarballScanner { collectables, maxConcurrency, logger, - workers + workers, + astAnalyserOptions } = options; this.#tempDir = tempDir; @@ -68,6 +74,7 @@ export class TarballScanner { this.#collectables = collectables; this.#collectableTypes = collectables.map((collectable) => collectable.type); this.#logger = logger; + this.#astAnalyserOptions = astAnalyserOptions ?? {}; this.#locker = new Mutex({ concurrency: maxConcurrency }); @@ -113,7 +120,8 @@ export class TarballScanner { fn: () => this.#workerPool!.scan({ location: mama.location!, astAnalyserOptions: { - optionalWarnings: hasLocation + optionalWarnings: hasLocation, + ...this.#astAnalyserOptions }, collectableTypes: this.#collectableTypes }), @@ -161,7 +169,8 @@ export class TarballScanner { fn: () => scanDirOrArchive(mama, ref, { astAnalyserOptions: { optionalWarnings: hasLocation, - collectables: this.#collectables + collectables: this.#collectables, + ...this.#astAnalyserOptions } }), onSuccess: (_, stat) => { diff --git a/workspaces/scanner/src/depWalker.ts b/workspaces/scanner/src/depWalker.ts index ed46911d..809ed9a1 100644 --- a/workspaces/scanner/src/depWalker.ts +++ b/workspaces/scanner/src/depWalker.ts @@ -131,7 +131,8 @@ export async function depWalker( npmRcEntries = {}, maxConcurrency = 8, workers, - integrity: manifestIntegrity = null + integrity: manifestIntegrity = null, + astAnalyserOptions } = options; const statsCollector = new StatsCollector({ logger }, { isVerbose }); @@ -236,7 +237,8 @@ export async function depWalker( collectables, maxConcurrency, logger, - workers + workers, + astAnalyserOptions }); const rootDepsOptions: npm.WalkOptions = { diff --git a/workspaces/scanner/src/index.ts b/workspaces/scanner/src/index.ts index 535d9441..e80fa8c6 100644 --- a/workspaces/scanner/src/index.ts +++ b/workspaces/scanner/src/index.ts @@ -5,6 +5,9 @@ import os from "node:os"; // Import Third-party Dependencies import pacote from "pacote"; +import type { + AstAnalyserOptions +} from "@nodesecure/js-x-ray"; import { getLocalRegistryURL } from "@nodesecure/npm-registry-sdk"; import * as tarball from "@nodesecure/tarball"; import { ManifestManager } from "@nodesecure/mama"; @@ -135,11 +138,20 @@ export async function from( ); } +export interface VerifyOptions { + astAnalyserOptions?: AstAnalyserOptions; +} + export async function verify( - spec?: string + spec?: string, + options: VerifyOptions = {} ): Promise { + const { astAnalyserOptions } = options; + if (typeof spec === "undefined") { - return tarball.scanPackage(process.cwd()); + return tarball.scanPackage(process.cwd(), { + astAnalyserOptions + }); } await using tempDir = await TempDirectory.create(); @@ -149,7 +161,9 @@ export async function verify( registry: getLocalRegistryURL() }); - const scanResult = await tarball.scanPackage(mama); + const scanResult = await tarball.scanPackage(mama, { + astAnalyserOptions + }); return scanResult; } diff --git a/workspaces/scanner/src/types.ts b/workspaces/scanner/src/types.ts index e9ac46c8..ca979b15 100644 --- a/workspaces/scanner/src/types.ts +++ b/workspaces/scanner/src/types.ts @@ -1,5 +1,8 @@ // Import Third-party Dependencies -import type { Warning } from "@nodesecure/js-x-ray"; +import type { + Warning, + AstAnalyserOptions +} from "@nodesecure/js-x-ray"; import type { StandardVulnerability, Kind } from "@nodesecure/vulnera"; import type { PackageModuleType } from "@nodesecure/mama"; @@ -282,6 +285,8 @@ export type SemverRange = string | "*"; export type HighlightPackages = string[] | Record; +export type AstAnalyserOptionsNoCollectable = Omit; + export interface Options { /** * Maximum tree depth @@ -364,6 +369,15 @@ export interface Options { * @default false */ readonly workers?: boolean | number; + + /** + * Custom options for the underhood JS-X-Ray instance + * when scanning tarballs or local directories + * + * @note + * Do not support `collectable` option + */ + readonly astAnalyserOptions?: AstAnalyserOptionsNoCollectable; } export interface TokenStore {