Compare commits

...

7 Commits

Author SHA1 Message Date
aab3ce213b v1.2.0
Some checks failed
Default (tags) / security (push) Failing after 17s
Default (tags) / test (push) Failing after 12s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-11-29 21:05:51 +00:00
6d02ef3ddc feat(core): Migrate to chokidar 5.x, add picomatch filtering and update test/dev dependencies 2025-11-29 21:05:51 +00:00
21827f06e9 1.1.1 2025-06-26 23:16:12 +00:00
b5133c2a9c fix(package.json): Add packageManager field to package.json for pnpm configuration 2025-06-26 23:16:12 +00:00
294420e0b2 1.1.0 2025-06-26 23:15:42 +00:00
d7a05abfa2 feat(Smartchok): Migrate to chokidar 4.x with picomatch glob support, update documentation and tests 2025-06-26 23:15:42 +00:00
3444b7c74d update description 2024-05-29 14:12:05 +02:00
10 changed files with 9388 additions and 4457 deletions

100
changelog.md Normal file
View File

@@ -0,0 +1,100 @@
# Changelog
## 2025-11-29 - 1.2.0 - feat(core)
Migrate to chokidar 5.x, add picomatch filtering and update test/dev dependencies
- Upgrade runtime dependencies: chokidar -> ^5.0.0 and picomatch -> ^4.0.3; bumped related @push.rocks packages versions.
- Upgrade devDependencies: @git.zone/tsbuild, @git.zone/tsrun and @git.zone/tstest to newer v2/v3 releases; updated @types/node.
- Updated README and readme.hints to document migration to chokidar 5.x and dev dependency changes.
- Tests updated to use @git.zone/tstest/tapbundle (import change) and test runner start changed to export default tap.start().
- Smartchok implementation updated to extract glob base paths, watch base directories and filter events via picomatch matchers (shouldWatchPath + event filtering).
- Note: ts/00_commitinfo_data.ts still references chokidar 4.x in the description and should be updated to reflect the migration.
## 2025-06-26 - 1.1.1 - fix(package.json)
Add packageManager field to package.json for pnpm configuration
- Added "packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977" to package.json
## 2025-06-26 - 1.1.0 - feat(Smartchok)
Migrate to chokidar 4.x with picomatch glob support, update documentation and tests
- Removed deprecated @tempfix/watcher and added chokidar and picomatch as dependencies in package.json
- Updated Smartchok class to extract base paths and apply custom glob filtering using picomatch
- Revised readme and technical hints to reflect migration to chokidar 4.x and clarify glob pattern support
- Adjusted tests and commit info to align with the updated code structure
## 2024-05-29 1.0.34 general
This release improves the project description.
- update description
## 2024-05-06 1.0.33 core
This release includes a mix of bug fixes and configuration updates.
- fix(core): update
- update tsconfig
- update npmextra.json: githost (recorded multiple times)
## 2024-02-29 1.0.32 to 1.0.28 core fixes
Releases 1.0.32 through 1.0.28 were dedicated to routine core fixes.
(This range covers versions that only included “fix(core): update” changes.)
## 2024-01-28 1.0.27 core
This release not only fixed core issues but also adjusted the organization scheme.
- fix(core): update
- switch to new org scheme (recorded twice)
## 2021-12-01 1.0.26 to 1.0.14 core fixes
Releases 1.0.26 through 1.0.14 were devoted to routine core fixes.
(No additional details beyond the core update were recorded.)
## 2018-02-28 1.0.13 to 1.0.11 ci updates
Releases 1.0.13 through 1.0.11 focused on updating the continuous integration configuration.
- update ci
## 2017-06-30 1.0.10 general
This release delivered several improvements beyond a simple version bump.
- fix Promise issues
- update test
- update
## 2017-06-30 1.0.9 general
This release addressed module loading and code hygiene.
- fix loading of rxjs
- clean up code
## 2017-06-30 1.0.8 general
A targeted update to align output with expectations.
- update to wirj like expected
## 2017-04-09 1.0.7 ci
An update to the continuous integration configuration.
- update ci
## 2017-04-09 1.0.6 npm
This release updated extra npm configuration.
- update npmextra.json
## 2017-02-15 1.0.5 general
Standardization work was undertaken with new organizational practices.
- update to new gitzone standard
## 2016-11-18 1.0.4 general
This release refreshed dependency settings.
- update dependencies
## 2016-11-18 1.0.3 general
Readability and developer guidance were improved.
- improve README
## 2016-11-18 1.0.2 general
Minor documentation and CI configuration enhancements were added.
- add README
- Update .gitlab-ci.yml
## 2016-09-22 1.0.1 general
A fix was applied to ensure the process exits correctly.
- fix process not exiting problem
## 2016-09-22 1.0.0 general
The projects initial setup was established along with CI configuration.
- add gitlab-ci
- initial

View File

@@ -1,8 +1,8 @@
{
"name": "@push.rocks/smartchok",
"version": "1.0.34",
"version": "1.2.0",
"private": false,
"description": "A smart wrapper for chokidar to facilitate file watching with enhanced features.",
"description": "A smart wrapper for chokidar 5.x with glob pattern support and enhanced features.",
"main": "dist_ts/index.js",
"typings": "dist_ts/index.d.ts",
"scripts": {
@@ -13,27 +13,27 @@
},
"repository": {
"type": "git",
"url": "git+https://gitlab.com/push.rocks/smartchok.git"
"url": "https://code.foss.global/push.rocks/smartchok.git"
},
"author": "Lossless GmbH",
"license": "MIT",
"bugs": {
"url": "https://gitlab.com/push.rocks/smartchok/issues"
},
"homepage": "https://gitlab.com/push.rocks/smartchok#readme",
"homepage": "https://code.foss.global/push.rocks/smartchok",
"dependencies": {
"@push.rocks/lik": "^6.0.2",
"@push.rocks/smartpromise": "^4.0.2",
"@push.rocks/smartrx": "^3.0.2",
"@tempfix/watcher": "^2.3.0"
"@push.rocks/lik": "^6.2.2",
"@push.rocks/smartpromise": "^4.2.3",
"@push.rocks/smartrx": "^3.0.10",
"chokidar": "^5.0.0",
"picomatch": "^4.0.3"
},
"devDependencies": {
"@git.zone/tsbuild": "^2.1.66",
"@git.zone/tsrun": "^1.2.44",
"@git.zone/tstest": "^1.0.77",
"@git.zone/tsbuild": "^3.1.2",
"@git.zone/tsrun": "^2.0.0",
"@git.zone/tstest": "^3.1.3",
"@push.rocks/smartfile": "^11.0.4",
"@push.rocks/tapbundle": "^5.0.8",
"@types/node": "^20.11.8"
"@types/node": "^24.10.1"
},
"files": [
"ts/**/*",
@@ -62,5 +62,6 @@
"file system events",
"real-time",
"watch files"
]
],
"packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977"
}

13260
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1 +1,33 @@
# smartchok - Technical Hints
## Chokidar 5.x Migration (2024)
The module has been migrated to `chokidar` 5.x (from 4.x). Key changes:
### Dependencies
- **Current**: `chokidar` 5.x and `picomatch`
- **Historical**: Was previously using `@tempfix/watcher` before chokidar 4.x
### Why picomatch?
Chokidar 4.x+ removed built-in glob pattern support. We use `picomatch` to maintain backward compatibility and provide glob pattern matching functionality.
### Implementation Details
1. **Glob pattern extraction**: The `getGlobBase()` method extracts base directories from glob patterns
2. **Pattern matching**: Each glob pattern is compiled to a picomatch matcher function
3. **Event filtering**: File system events are filtered based on glob patterns before being emitted
4. **Path normalization**: Paths are normalized to handle different formats (with/without leading ./)
### Event Handling
Chokidar 5.x events are mapped 1:1 with smartchok events:
- `add`, `change`, `unlink`: File events
- `addDir`, `unlinkDir`: Directory events
- `error`: Error events
- `raw`: Raw events from underlying watchers
- `ready`: Emitted when initial scan is complete
### Testing
All existing tests pass without modification, confirming backward compatibility is maintained.
## Dev Dependencies (2024)
- Using `@git.zone/tstest` v3.x with tapbundle (`import { tap, expect } from '@git.zone/tstest/tapbundle'`)
- Removed deprecated `@push.rocks/tapbundle`

220
readme.md
View File

@@ -1,117 +1,191 @@
# @push.rocks/smartchok
smart wrapper for chokidar
A smart wrapper for chokidar 5.x with glob pattern support, RxJS observable integration, and enhanced file watching features.
## Issue Reporting and Security
For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
## Install
Install the package by running the following command in your terminal:
```sh
npm install @push.rocks/smartchok --save
npm install @push.rocks/smartchok
# or
pnpm add @push.rocks/smartchok
```
This command adds `@push.rocks/smartchok` to your project's dependencies, ensuring that your project can use its functionality and that it will be installed when running `npm install` in your project root.
## Features
🔍 **Glob Pattern Support** - Watch files using glob patterns like `**/*.ts` or `src/**/*.js`
📡 **RxJS Observables** - Subscribe to file system events using reactive streams
🔄 **Dynamic Watching** - Add or remove watch patterns at runtime
**Chokidar 5.x** - Built on the latest chokidar with improved performance
🎯 **TypeScript First** - Full TypeScript support with comprehensive type definitions
## Usage
The `@push.rocks/smartchok` package provides a convenient and smart wrapper around the popular `chokidar` library for file watching with enhanced features such as observable support for filesystem events. This guide will introduce you to the usage of `@push.rocks/smartchok`, leveraging TypeScript for type safety and better developer experience.
### Setting Up Your Project
To use `@push.rocks/smartchok`, ensure your project is set up to use TypeScript and ECMAScript modules (ESM). You need to have a `tsconfig.json` file at the root of your project with the following minimum settings:
```json
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"esModuleInterop": true,
"declaration": true,
"outDir": "./dist",
"strict": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
```
This configuration enables TypeScript compilation targeting the latest ECMAScript standards and includes all TypeScript files (`*.ts`) in your `src` directory.
### Basic Setup
To start using `smartchok`, first import it into your TypeScript file:
```typescript
import { Smartchok } from '@push.rocks/smartchok';
```
#### Initializing Smartchok
Create an instance of `Smartchok` by specifying an array of glob patterns to watch:
```typescript
const smartchokInstance = new Smartchok([
'./src/**/*.ts', // Watch all TypeScript files in the src directory
'./public/assets/**/*' // Watch all files in the public/assets directory
// Create a watcher with glob patterns
const watcher = new Smartchok([
'./src/**/*.ts', // Watch all TypeScript files in src
'./public/assets/**/*' // Watch all files in public/assets
]);
// Start watching
await watcher.start();
```
#### Adding and Removing Files Dynamically
### Subscribing to File Events
You can dynamically add and remove paths from being watched by using the `add` and `remove` methods:
Use RxJS observables to react to file system changes:
```typescript
// Add additional files or patterns
smartchokInstance.add(['./tests/**/*.spec.ts']);
// Remove specific patterns from watch
smartchokInstance.remove('./src/**/*.test.ts');
```
#### Handling Filesystem Events
`smartchok` leverages RxJS observables to notify about filesystem events. This allows you to respond to various events such as file additions, changes, and deletions with ease.
First, start the watcher:
```typescript
await smartchokInstance.start();
```
Then, subscribe to an event:
```typescript
const changeObservable = await smartchokInstance.getObservableFor('change');
// Get an observable for file changes
const changeObservable = await watcher.getObservableFor('change');
changeObservable.subscribe({
next: ([path, stats]) => {
console.log(`File changed: ${path}`);
},
error: (err) => {
console.error(`An error occurred: ${err}`);
console.error(`Error: ${err}`);
}
});
// Watch for new files
const addObservable = await watcher.getObservableFor('add');
addObservable.subscribe(([path]) => {
console.log(`File added: ${path}`);
});
// Watch for deleted files
const unlinkObservable = await watcher.getObservableFor('unlink');
unlinkObservable.subscribe(([path]) => {
console.log(`File deleted: ${path}`);
});
```
Supported events include 'add', 'change', 'unlink' (for deletions), and others. Refer to the chokidar documentation for a full list of events.
### Supported Events
#### Stopping the Watcher
| Event | Description |
|-------|-------------|
| `add` | File has been added |
| `addDir` | Directory has been added |
| `change` | File has been changed |
| `unlink` | File has been removed |
| `unlinkDir` | Directory has been removed |
| `error` | Error occurred |
| `ready` | Initial scan complete |
| `raw` | Raw event from the underlying watcher |
To stop watching for file changes, simply call:
### Dynamic Watch Management
Add or remove patterns while the watcher is running:
```typescript
await smartchokInstance.stop();
const watcher = new Smartchok(['./src/**/*.ts']);
await watcher.start();
// Add more patterns to watch
watcher.add(['./tests/**/*.spec.ts', './config/*.json']);
// Remove a pattern
watcher.remove('./src/**/*.test.ts');
```
### Advanced Usage
### Stopping the Watcher
Beyond the basics, `smartchok` allows for more complex monitoring scenarios, such as debounced notifications for rapid changes, filtering events, and integrating with other observables for complex asynchronous workflows.
```typescript
// Stop watching when done
await watcher.stop();
```
### Conclusion
### Complete Example
`@push.rocks/smartchok` provides a robust, observable-based wrapper around `chokidar`, making it an excellent choice for projects requiring efficient and flexible file monitoring. Its integration with RxJS opens up a wide array of possibilities for handling file system events in a reactive manner, making your code more concise, readable, and maintainable.
```typescript
import { Smartchok } from '@push.rocks/smartchok';
By following the guidelines provided in this document, you should now be equipped to integrate `@push.rocks/smartchok` into your TypeScript project, enhancing its capabilities with efficient file system monitoring.
async function watchProject() {
// Initialize with patterns
const watcher = new Smartchok([
'./src/**/*.ts',
'./package.json'
]);
// Start the watcher
await watcher.start();
console.log('👀 Watching for changes...');
// Subscribe to changes
const changes = await watcher.getObservableFor('change');
changes.subscribe(([path, stats]) => {
console.log(`📝 Modified: ${path}`);
console.log(` Size: ${stats?.size ?? 'unknown'} bytes`);
});
// Subscribe to new files
const additions = await watcher.getObservableFor('add');
additions.subscribe(([path]) => {
console.log(`✨ New file: ${path}`);
});
// Subscribe to deletions
const deletions = await watcher.getObservableFor('unlink');
deletions.subscribe(([path]) => {
console.log(`🗑️ Deleted: ${path}`);
});
// Handle graceful shutdown
process.on('SIGINT', async () => {
console.log('\n🛑 Stopping watcher...');
await watcher.stop();
process.exit(0);
});
}
watchProject();
```
## How It Works
Since chokidar 4.x+ no longer supports glob patterns natively, smartchok handles glob pattern matching internally using [picomatch](https://github.com/micromatch/picomatch). This means you get the familiar glob syntax while benefiting from chokidar's efficient file watching capabilities.
When you provide glob patterns:
1. **Base path extraction** - smartchok extracts the static base path from each pattern
2. **Efficient watching** - chokidar watches the base directories
3. **Pattern filtering** - Events are filtered through picomatch matchers before being emitted
## API Reference
### `Smartchok`
#### Constructor
```typescript
new Smartchok(patterns: string[])
```
Creates a new Smartchok instance with the given glob patterns.
#### Methods
| Method | Returns | Description |
|--------|---------|-------------|
| `start()` | `Promise<void>` | Starts watching for file changes |
| `stop()` | `Promise<void>` | Stops the file watcher |
| `add(patterns: string[])` | `void` | Adds patterns to watch |
| `remove(pattern: string)` | `void` | Removes a pattern from watching |
| `getObservableFor(event: TFsEvent)` | `Promise<Observable<[string, Stats]>>` | Returns an RxJS observable for the specified event |
#### Properties
| Property | Type | Description |
|----------|------|-------------|
| `status` | `'idle' \| 'starting' \| 'watching'` | Current watcher status |
## License and Legal Information

70
readme.plan.md Normal file
View File

@@ -0,0 +1,70 @@
# Migration Plan: smartchok to Chokidar 4.x
Command to reread CLAUDE.md: `cat /home/philkunz/.claude/CLAUDE.md`
## MIGRATION COMPLETED ✅
All phases of the migration have been successfully completed:
## Current State Analysis
- **Current dependency**: `@tempfix/watcher` v2.3.0 (a fork of fabiospampinato/watcher)
- **Target**: Chokidar v4.0.3
- **Major challenge**: Chokidar 4.x removed glob support, but smartchok heavily uses glob patterns
## Migration Plan
### Phase 1: Preparation
1. Install chokidar 4.x and glob library for pattern matching
- `pnpm install chokidar@^4.0.3`
- `pnpm install picomatch` (for glob pattern matching)
- `pnpm uninstall @tempfix/watcher`
### Phase 2: Code Changes
#### 2.1 Update Plugin Imports (ts/smartchok.plugins.ts)
- Remove `@tempfix/watcher` import
- Add `chokidar` import
- Add `picomatch` for glob pattern matching
#### 2.2 Update Smartchok Class (ts/smartchok.classes.smartchok.ts)
- Replace watcher initialization with chokidar
- Implement custom glob filtering using picomatch
- Update event mapping to match chokidar's event names
- Adjust watcher options to match chokidar's API
#### 2.3 Handle Glob Patterns
Since chokidar 4.x removed glob support, we need to:
- Parse glob patterns to extract base directories
- Use chokidar to watch base directories
- Use picomatch to filter events based on glob patterns
- Ensure backward compatibility with existing API
#### 2.4 Event Mapping
Map chokidar events to existing smartchok events:
- Keep existing event names for backward compatibility
- Ensure all current functionality is preserved
### Phase 3: Testing
1. Run existing tests to ensure backward compatibility
2. Add new tests for glob pattern handling
3. Test edge cases with complex glob patterns
4. Verify performance with large file sets
### Phase 4: Documentation
1. Update readme.md to reflect the change to chokidar 4.x
2. Document any API changes (if any)
3. Update version number in package.json
## Technical Details
### Key Differences to Handle:
1. **Glob Support**: Implement custom glob filtering layer
2. **API Changes**: Adapt initialization and option passing
3. **Event Names**: Map between different event naming conventions
4. **Minimum Node Version**: Ensure compatibility with Node 14+
### Risk Mitigation:
- Maintain backward compatibility with existing API
- Extensive testing with current test suite
- Consider keeping a legacy branch if breaking changes are unavoidable

View File

@@ -1,4 +1,4 @@
import { tap, expect } from '@push.rocks/tapbundle';
import { tap, expect } from '@git.zone/tstest/tapbundle';
import * as smartchok from '../ts/index.js';
import * as smartfile from '@push.rocks/smartfile';
import * as smartpromise from '@push.rocks/smartpromise';
@@ -47,4 +47,4 @@ tap.test('should stop the watch process', async (tools) => {
testSmartchok.stop();
});
tap.start();
export default tap.start();

View File

@@ -1,8 +1,8 @@
/**
* autocreated commitinfo by @pushrocks/commitinfo
* autocreated commitinfo by @push.rocks/commitinfo
*/
export const commitinfo = {
name: '@push.rocks/smartchok',
version: '1.0.34',
description: 'A smart wrapper for chokidar to facilitate file watching with enhanced features.'
version: '1.2.0',
description: 'A smart wrapper for chokidar 5.x with glob pattern support and enhanced features.'
}

View File

@@ -18,7 +18,9 @@ export type TFsEvent =
export class Smartchok {
public watchStringmap = new Stringmap();
public status: TSmartchokStatus = 'idle';
private watcher: plugins.watcher;
private watcher: plugins.chokidar.FSWatcher;
private globPatterns: string[] = [];
private globMatchers: Map<string, (path: string) => boolean> = new Map();
private watchingDeferred = plugins.smartpromise.defer<void>(); // used to run things when watcher is initialized
private eventObservablemap = new plugins.smartrx.Observablemap(); // register one observable per event
@@ -94,17 +96,72 @@ export class Smartchok {
public start(): Promise<void> {
const done = plugins.smartpromise.defer<void>();
this.status = 'starting';
this.watcher = new plugins.watcher(
this.watchStringmap.getStringArray().map((string) => {
const result = this.getGlobBase(string);
console.log(`Watching ${result} for changes`);
return result;
}),
{
depth: 4,
recursive: true,
// Store original glob patterns and create matchers
this.globPatterns = this.watchStringmap.getStringArray();
const basePaths = new Set<string>();
this.globPatterns.forEach((pattern) => {
const basePath = this.getGlobBase(pattern);
basePaths.add(basePath);
// Create a picomatch matcher for each glob pattern
const matcher = plugins.picomatch(pattern, {
dot: true,
basename: false
});
this.globMatchers.set(pattern, matcher);
});
// Convert Set to Array for chokidar
const watchPaths = Array.from(basePaths);
console.log('Base paths to watch:', watchPaths);
this.watcher = plugins.chokidar.watch(watchPaths, {
persistent: true,
ignoreInitial: false,
followSymlinks: false,
depth: 4,
awaitWriteFinish: {
stabilityThreshold: 300,
pollInterval: 100
},
ignored: (path: string, stats?: plugins.fs.Stats) => {
// Don't filter during initialization - let chokidar watch everything
// We'll filter events as they come in
return false;
}
);
});
// Set up event handlers with glob filtering
const fileEvents: Array<'add' | 'change' | 'unlink' | 'addDir' | 'unlinkDir'> =
['add', 'addDir', 'change', 'unlink', 'unlinkDir'];
// Handle file events
fileEvents.forEach(eventName => {
this.watcher.on(eventName, (path: string, stats?: plugins.fs.Stats) => {
// Only emit event if the path matches our glob patterns
if (this.shouldWatchPath(path)) {
this.eventObservablemap.getSubjectForEmitterEvent(this.watcher, eventName)
.next([path, stats]);
}
});
});
// Handle error events
this.watcher.on('error', (error: Error) => {
this.eventObservablemap.getSubjectForEmitterEvent(this.watcher, 'error')
.next([error, undefined]);
});
// Handle raw events
this.watcher.on('raw', (eventType: string, path: string, details: any) => {
if (this.shouldWatchPath(path)) {
this.eventObservablemap.getSubjectForEmitterEvent(this.watcher, 'raw')
.next([path, undefined]);
}
});
this.watcher.on('ready', () => {
this.status = 'watching';
this.watchingDeferred.resolve();
@@ -128,4 +185,36 @@ export class Smartchok {
await closeWatcher();
}
}
/**
* Checks if a path should be watched based on glob patterns
*/
private shouldWatchPath(filePath: string): boolean {
// Normalize the path - remove leading ./ if present
let normalizedPath = filePath.replace(/\\/g, '/');
if (normalizedPath.startsWith('./')) {
normalizedPath = normalizedPath.substring(2);
}
// Check if the path matches any of our glob patterns
for (const [pattern, matcher] of this.globMatchers) {
// Also normalize the pattern for comparison
let normalizedPattern = pattern;
if (normalizedPattern.startsWith('./')) {
normalizedPattern = normalizedPattern.substring(2);
}
// Try matching with both the original pattern and normalized
if (matcher(normalizedPath) || matcher(filePath)) {
return true;
}
// Also try matching without the leading path
const withoutLeading = 'test/' + normalizedPath.split('test/').slice(1).join('test/');
if (matcher(withoutLeading)) {
return true;
}
}
return false;
}
}

View File

@@ -19,9 +19,10 @@ export {
}
// thirdparty scope
// @ts-nocheck
import watcher from '@tempfix/watcher';
import * as chokidar from 'chokidar';
import picomatch from 'picomatch';
export {
watcher,
chokidar,
picomatch,
}