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 🙏

© 2025 – Pkg Stats / Ryan Hefner

project-watcher

v0.2.5

Published

Watch on project structure

Downloads

28

Readme

npm package

Project watcher

Watch on project files and filesystem events.
Easily automate some routines.

Use case:

  • Use template when creating new react block. video
  • Auto update exports in index file. video

Full TypeScript support.

Uses chokidar for fs observing.
For all path rules minimatch used.

While still in development, use --save-exact to prevent updating with breaking changes.

Integration

Install

npm i project-watcher --save-exact

Create watcher script

const path = require('path');
const { ProjectWatcher } = require('project-watcher');

// project paths
const projectSource = path.join(__dirname, '../src');
const projectBlockTemplate = path.join(__dirname, '../templates/block');
const projectBlockFileTemplate = path.join(__dirname, '../templates/block.tsx');

new ProjectWatcher(projectSource, {
    watcher: {},
    paths: {
        "**/blocks/*": {
            autoIndex: 'ts',
            excludeIndex: [ '*.scss', '*.scss.d.ts' ],
            newDirTemplate: projectBlockTemplate,
        },
        "**/blocks/*.tsx": {
            newFileTemplate: projectBlockFileTemplate,
        }
    }
});

Now run watcher script with development environment.

Every time you create folder in any blocks/ folder, it will be filled with template.
Every time you create file in blocks/, it will be filled with template from file.
Every time you create/delete/rename something in blocks/, index.ts file will be auto-updated.

API

ProjectWatcher

constructor(rootPath: string | string[], opts: ProjectWatcherOptions, logger: ILogger = DefaultLogger.instance);
  • rootPath - Path or paths to project's root directories that will be watched.
  • opts - Configuration (see below).
  • logger - ILogger instance that will be used for all log messages.
type ProjectWatcherOptions = {
    watcher?: WatcherOptions,
    paths: { [pathRule: string]: ProjectWatcherPathOptions },
}
  • watcher - Chokidar watch options (chokidar.WatchOptions).
  • paths - Map of paths & it's processing options.

ProjectWatcherOptions is

type ProjectWatcherOptions = {

    // FileSystem events custom handlers

    newDir?: (path: string) => any,
    newFile?: (path: string) => any,
    renameFile?: (oldPath: string, newPath: string) => any,
    renameDir?: (oldPath: string, newPath: string) => any,
    removeDir?: (path: string) => any,
    removeFile?: (path: string) => any,
    changeFile?: (path: string) => any,

    // Automation

    break?: boolean,
    breakCustomEvents?: boolean,
    autoIndex?: boolean|'js'|'ts',
    dontCreateIndex?: boolean,
    excludeIndex?: string[],
    newDirTemplate?: string,
    newFileTemplate?: string,
    replace?: ReplacementMap,
    replaceFileName?: ReplacementMap,
}

You can observe any of filesystem events.
Callbacks are async and if you return Promise from it, project-watcher will wait until promise will be resolved.

  • break - Will stop event propogation for other similar paths (doesnt effect custom handlers).
  • breakCustomEvents - Will stop event propogation for custom handlers.
  • autoIndex - Auto update exports in index files. Use js or ts to specify index's extension. (ts by default).
  • dontCreateIndex - If autoIndex=true dont create index file if it is not exists.
  • excludeIndex - Excludes some paths or file names from indexing in autoIndex.
  • newDirTemplate - Path to directory with template code. If new dir is created on matched path, it will be populated with this template. Use replace & replaceFileName to tweak this template.
  • newFileTemplate - Path to file with template code. If new dir is created on matched path, it will be populated with this template. Use replace & replaceFileName to tweak this template.
  • replace - Replace text in templates (see more info below).
  • replaceFileName - Rename files of directory template (see more info below).

Replacement map for template's files.
Applied before ProjectWatcherOptions.replace.

type ReplacementMap = {
    [from: string]: 
        string|
        ((info: {
            // full path to dst file name
            // eg '/c/project/a.ts'
            filePath: string,

            // file's base name (without path & extension)
            // eg 'a'
            fileName: string,

            // file's extension
            // eg '.ts'
            fileExt: string,

            // path to dst file
            // eg '/c/project'
            targetDirName: string
        }) => string)
}

'from' is matching fully filenames in templates directory, without extensions (when populating new directory with template code).

Example

When creating dir like 'blocks/myBlock'
And template file copied from 'template/NAME.js'

with:

replaceFileName: {
    NAME: ({ targetDirName }) => `${targetDirName}.js`,
}

File will be copied as 'blocks/myBlock/myBlock.js'

Replacement map to text in templates.
Applied after ProjectWatcherOptions.replaceFileName.

type ReplacementMap = {
    [from: string]: 
        string|
        ((info: {
            // full path to dst file name
            // eg '/c/project/a.ts'
            filePath: string,

            // file's base name (without path & extension)
            // eg 'a'
            fileName: string,

            // file's extension
            // eg '.ts'
            fileExt: string,

            // path to dst file
            // eg '/c/project'
            targetDirName: string
        }) => string)
}

When from is matched, replaces to string or 'transformer' func.

!! replace used after replaceFileName, so filePath & fileName may be transformed. !!

Example

new ProjectWatcher(projectSource, {
    watcher: {},
    paths: {
        "**/blocks/*": {
            autoIndex: 'ts',
            excludeIndex: [ '*.scss', '*.scss.d.ts' ],
            newDirTemplate: projectBlockTemplate,
            replace: {
                'COMPONENT_NAME': ({ targetDirName }) => path.basename(targetDirName),
            },
        },
        "**/blocks/*.tsx": {
            newFileTemplate: projectBlockFileTemplate,
            replace: {
                'COMPONENT_NAME': ({ fileName }) => fileName,
            },
        }
    }
});

Now when you create new .tsx file or new directory in blocks,
Exports will be auto-updated, and in all file COMPONENT_NAME will be replaced to file name or directory name.