npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@angular-modernizer/worker

v1.2.0

Published

Worker thread script for parallel analysis in the Angular Modernization Platform

Readme

@angular-modernizer/worker

Worker thread script for parallel analysis in the Angular Modernization Platform.

Overview

@angular-modernizer/core can run analysis rules in Node.js worker threads (WorkerPool, ParallelExecutor). Each worker is started from a script file. That script lives in this package, and getWorkerScriptPath() returns its path.

The package exports:

  • getWorkerScriptPath() - absolute path to the compiled worker script (dist/analysis-worker.js)
  • WorkerTask, WorkerResult - message types, re-exported from @angular-modernizer/core

The script itself is also published as the subpath export @angular-modernizer/worker/analysis-worker. It can only run as a worker thread; importing it on the main thread throws.

Why a Separate Package?

Worker threads run in isolated V8 contexts, so the worker script has to load all analysis plugins itself. The plugins depend on core, and core contains the WorkerPool. Placing the script in core would create a circular dependency.

This package resolves that by:

  1. Depending on all plugin packages (it builds after them)
  2. Exporting a helper that returns the worker script path
  3. Being used by both programmatic API users and the MCP adapter (scan-architecture passes the path to the parallel executor)

Installation

pnpm add @angular-modernizer/worker @angular-modernizer/core

The worker script is loaded from dist/, so in the monorepo all workspace packages must be built first (pnpm build from the root).

Usage

With the ParallelExecutor

ParallelExecutor decides on its own whether to use worker threads (see Mode Selection). Pass the script path, the tsconfig the workers load and the plugin IDs whose rules the workers run:

import { getWorkerScriptPath } from '@angular-modernizer/worker';
import { ParallelExecutor } from '@angular-modernizer/core';

const executor = new ParallelExecutor({ maxWorkers: 4 });

const results = await executor.executeParallel(sourceFiles, rules, {
  tsConfigPath: '/path/to/tsconfig.json',
  workerScriptPath: getWorkerScriptPath(),
  pluginIds: ['architecture', 'solid'],
});

await executor.shutdown();

With the WorkerPool directly

import { getWorkerScriptPath } from '@angular-modernizer/worker';
import { WorkerPool } from '@angular-modernizer/core';

const pool = new WorkerPool({
  tsConfigPath: '/path/to/tsconfig.json',
  workerScriptPath: getWorkerScriptPath(),
  maxWorkers: 4,
});

const result = await pool.executeTask({
  id: 'task-1',
  type: 'analyze-rule',
  filePath: '/path/to/file.ts',
  ruleIds: [], // empty: all rules of the listed plugins
  pluginIds: ['architecture', 'solid'],
});

if (result.error) {
  console.error(result.error);
}
console.log(result.results);

await pool.terminate();

WorkerPool throws when workerScriptPath is missing.

How Workers Run

Each worker started from the script:

  1. Reads workerId and tsConfigPath from workerData and loads the whole project from that tsconfig into its own ts-morph Project. Rules need cross-file context (inheritance, imports), so a worker does not load single files.
  2. Creates its own PublicApi and posts { type: 'ready', workerId }. If loading fails, it posts { type: 'init-error', workerId, error } and exits. The pool only hands out tasks to workers that sent ready.
  3. Receives WorkerTask messages and answers each with a WorkerResult.

For a task the worker:

  • loads the analysis rules of the plugins in pluginIds; rules are cached per plugin ID for later tasks
  • keeps only the rules listed in ruleIds when that list is not empty
  • builds the context with ContextFactory.createAnalysisContext() and runs the rules on filePath
  • returns the results with the severity warning (plugin results carry no severity)

Accepted plugin IDs:

| Plugin ID | Package | |-|-| | architecture | @angular-modernizer/plugin-architecture | | solid | @angular-modernizer/plugin-solid | | angular | @angular-modernizer/plugin-angular | | analyzer | @angular-modernizer/plugin-analyzer | | standalone | @angular-modernizer/plugin-standalone (no analysis rules) |

The full package name works as well. Unknown IDs are logged and ignored. With no matching rules the task returns an empty result list, so pass pluginIds: the ParallelExecutor sends an empty list when pluginIds is not set.

Errors:

  • A rule that throws is logged and skipped; the other rules still run.
  • A task fails (empty results, error set) when filePath is not part of the loaded project or the worker is not initialized.
  • An uncaught exception or unhandled rejection in a worker posts init-error and ends the worker.

Workers log to the console with the prefix [Worker <id>].

Mode Selection

ParallelExecutor.executeParallel() chooses between Promise-based parallelism on the main thread and worker threads. With autoSelectMode (default) and no useWorkerThreads, it computes a complexity score from 0 to 100:

| Factor | Weight | |-|-| | File count (2000 files = 100) | 30% | | Estimated lines of code (1M = 100) | 35% | | Large files over 50 KB | 20% | | Current heap usage above 70% | 15% |

| Score | Mode | |-|-| | below 35 | Promise mode | | 35 to below 50 | Promise mode with memory monitoring; aborts when heap usage reaches 85% and falls back to workers if workerScriptPath is set | | 50 and above | Worker threads |

Overrides:

  • useWorkerThreads: true uses workers when there are at least minFilesForWorkers files (default 200), otherwise Promise mode
  • useWorkerThreads: false always uses Promise mode
  • autoSelectMode: false without useWorkerThreads uses Promise mode

If worker execution fails, the executor terminates the pool and falls back to Promise mode.

Details: docs/architecture/parallelism.md.

Limits

| Setting | Default | |-|-| | Workers (WorkerPool) | CPU cores - 1, at least 1 | | Heap per worker (WorkerPool, workerHeapLimit) | 512 MB old generation; ParallelExecutor sets 4096 MB | | Task timeout (defaultTimeout / timeout) | 30000 ms, counted from the moment a worker is ready | | Wait for the first ready worker | 120 s |

Each worker loads the full project, so memory grows with the number of workers. A worker that hits its heap limit is ended by Node.js; lower maxWorkers or raise workerHeapLimit for large projects. Workers do not report their heap usage, so the pool cannot recycle them based on real memory use.

Data crossing the thread boundary is copied with the structured clone algorithm. Use plain objects, primitives and arrays: functions and Symbols cause a DataCloneError, class instances arrive as plain objects without their methods. WorkerTask.config must follow this rule.

Build Order

This package builds after all plugins in the monorepo:

1. core
2. plugin-system
3. api
4. plugin-analyzer, plugin-solid, plugin-angular, plugin-standalone, plugin-architecture, orchestration
5. worker (this package)
6. adapter-mcp

Testing

The package has no tests of its own. The worker pool tests live in @angular-modernizer/core and are skipped unless ENABLE_WORKER_TESTS=true is set and the worker script is built:

pnpm run build
ENABLE_WORKER_TESTS=true pnpm --filter @angular-modernizer/core test

Dependencies

  • @angular-modernizer/core - WorkerTask, WorkerResult
  • @angular-modernizer/api - createPublicApi for each worker
  • @angular-modernizer/plugin-system - ContextFactory, rule contracts
  • @angular-modernizer/plugin-analyzer, plugin-solid, plugin-angular, plugin-standalone, plugin-architecture - rules run in workers
  • ts-morph - project loading

See Also