diff --git a/.changeset/colorless-green-ideas.md b/.changeset/colorless-green-ideas.md new file mode 100644 index 00000000..8ca4c06f --- /dev/null +++ b/.changeset/colorless-green-ideas.md @@ -0,0 +1,5 @@ +--- +"@nodesecure/scanner": minor +--- + +feat(extractor): Extends eventTarget instead of eventEmitter for browser compatibility \ No newline at end of file diff --git a/workspaces/scanner/src/extractors/payload.ts b/workspaces/scanner/src/extractors/payload.ts index b425d335..00379dc8 100644 --- a/workspaces/scanner/src/extractors/payload.ts +++ b/workspaces/scanner/src/extractors/payload.ts @@ -1,6 +1,3 @@ -// Import Node.js Dependencies -import { EventEmitter } from "node:events"; - // Import Third-party Dependencies import type { Simplify } from "type-fest"; // @ts-ignore @@ -53,7 +50,7 @@ export interface ManifestProbeExtractor extends ProbeExtractor { next: ManifestProbeNextCallback; } -export class Payload[]> extends EventEmitter { +export class Payload[]> extends EventTarget { private dependencies: Scanner.Payload["dependencies"]; private probes: Record; private cachedResult: ExtractProbeResult; @@ -82,6 +79,7 @@ export class Payload[]> extends EventEmitter { for (const [name, dependency] of Object.entries(this.dependencies)) { this.probes.packument.forEach((probe) => probe.next(name, dependency)); this.emit("packument", name, dependency); + if (this.probes.manifest.length > 0) { for (const [spec, depVersion] of Object.entries(dependency.versions)) { this.probes.manifest.forEach((probe) => probe.next(spec, depVersion, { name, dependency })); @@ -103,6 +101,29 @@ export class Payload[]> extends EventEmitter { ...this.extract() ) as unknown as MergedExtractProbeResult; } + + emit( + event: T, + ...extractionDetails: unknown[] + ) { + const customEvent = new CustomEvent(event, { + detail: extractionDetails + }); + this.dispatchEvent(customEvent); + } + + on( + e: T, + listener: ExtractorListener + ): this { + function wrappedListener(event: Event) { + const customEvent = event as CustomEvent>; + listener(...customEvent.detail); + } + this.addEventListener(e, wrappedListener); + + return this; + } } export const Callbacks = { @@ -126,6 +147,18 @@ export const Callbacks = { } } as const; +type ExtractorCallback = Parameters< + (typeof Callbacks)[T] +>[0]; + +export type ExtractorCallbackParams = Parameters< + ExtractorCallback +>; + +export type ExtractorListener = ( + ...events: CustomEvent>["detail"] +) => void; + function noop() { return void 0; } diff --git a/workspaces/scanner/test/extractors/payload.spec.ts b/workspaces/scanner/test/extractors/payload.spec.ts index 896417f0..22500201 100644 --- a/workspaces/scanner/test/extractors/payload.spec.ts +++ b/workspaces/scanner/test/extractors/payload.spec.ts @@ -1,16 +1,12 @@ // Import Node.js Dependencies -import { describe, it } from "node:test"; import assert from "node:assert"; -import path from "node:path"; import fs from "node:fs"; +import path from "node:path"; +import { describe, it } from "node:test"; // Import Internal Dependencies -import { - Extractors, - type ManifestProbeNextCallback, - type PackumentProbeNextCallback, - type Payload -} from "../../src/index.js"; +import { type ExtractorCallbackParams } from "../../src/extractors/payload.js"; +import { Extractors, type Payload } from "../../src/index.js"; // CONSTANTS const kFixturePath = path.join("fixtures", "extractors"); @@ -220,16 +216,11 @@ describe("Extractors.Probes", () => { } }; - const extractor = new Extractors.Payload( - fakePayload, - [ - new Extractors.Probes.Vulnerabilities() - ] - ); + const extractor = new Extractors.Payload(fakePayload, [ + new Extractors.Probes.Vulnerabilities() + ]); - const { - vulnerabilities - } = extractor.extractAndMerge(); + const { vulnerabilities } = extractor.extractAndMerge(); assert.strictEqual(vulnerabilities.length, 2); assert.deepEqual(vulnerabilities, ["foo", "bar"]); @@ -237,13 +228,11 @@ describe("Extractors.Probes", () => { }); it("should extract data with multiple extractors in once", () => { - const extractor = new Extractors.Payload( - expressNodesecurePayload, - [ - new Extractors.Probes.Size(), - new Extractors.Probes.Contacts(), - new Extractors.Probes.Licenses() - ] + const extractor = new Extractors.Payload(expressNodesecurePayload, [ + new Extractors.Probes.Size(), + new Extractors.Probes.Contacts(), + new Extractors.Probes.Licenses() + ] ); const arrResult = extractor.extract(); @@ -258,9 +247,6 @@ describe("Extractors.Probes", () => { }); describe("Extractors.Payload events", () => { - type ManifestEvent = Parameters; - type PackumentEvent = Parameters; - it("should emits packument and manifest events", () => { const extractor = new Extractors.Payload( expressNodesecurePayload, @@ -270,14 +256,14 @@ describe("Extractors.Payload events", () => { ] ); - const manifestEvents: ManifestEvent[] = []; - const packumentEvents: PackumentEvent[] = []; + const manifestEvents: ExtractorCallbackParams<"manifest">[] = []; + const packumentEvents: ExtractorCallbackParams<"packument">[] = []; - extractor.on("manifest", (...event: ManifestEvent) => { + extractor.on("manifest", (...event) => { manifestEvents.push(event); }); - extractor.on("packument", (...event: PackumentEvent) => { + extractor.on("packument", (...event) => { packumentEvents.push(event); }); @@ -301,20 +287,18 @@ describe("Extractors.Callbacks", () => { it("should extract name and versions for all packages", () => { const packages = new Map(); - const extractor = new Extractors.Payload( - expressNodesecurePayload, - [ - Extractors.Callbacks.packument((name) => { - if (!packages.has(name)) { - packages.set(name, []); - } - }), - Extractors.Callbacks.manifest((spec, _, parent) => { - if (packages.has(parent.name)) { - packages.get(parent.name)!.push(spec); - } - }) - ] + const extractor = new Extractors.Payload(expressNodesecurePayload, [ + Extractors.Callbacks.packument((name) => { + if (!packages.has(name)) { + packages.set(name, []); + } + }), + Extractors.Callbacks.manifest((spec, _, parent) => { + if (packages.has(parent.name)) { + packages.get(parent.name)!.push(spec); + } + }) + ] ); extractor.extract();