@photostructure/fs-metadata 0.6.1 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -1
- package/CLAUDE.md +141 -315
- package/CODE_OF_CONDUCT.md +11 -11
- package/CONTRIBUTING.md +1 -1
- package/README.md +34 -103
- package/binding.gyp +97 -22
- package/claude.sh +23 -0
- package/dist/index.cjs +51 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.mjs +51 -21
- package/dist/index.mjs.map +1 -1
- package/doc/C++_REVIEW_TODO.md +97 -25
- package/doc/GPG_RELEASE_HOWTO.md +44 -13
- package/doc/MACOS_API_REFERENCE.md +469 -0
- package/doc/SECURITY_AUDIT_2025.md +809 -0
- package/doc/SSH_RELEASE_HOWTO.md +28 -24
- package/doc/WINDOWS_API_REFERENCE.md +422 -0
- package/doc/WINDOWS_ARM64_SECURITY.md +161 -0
- package/doc/WINDOWS_DEBUG_GUIDE.md +9 -2
- package/doc/examples.md +267 -0
- package/doc/gotchas.md +297 -0
- package/doc/logo.png +0 -0
- package/doc/logo.svg +85 -0
- package/doc/macos-asan-sip-issue.md +71 -0
- package/doc/social.png +0 -0
- package/doc/social.svg +125 -0
- package/doc/windows-build.md +226 -0
- package/doc/windows-clang-tidy.md +72 -0
- package/doc/windows-memory-testing.md +108 -0
- package/doc/windows-prebuildify-arm64.md +232 -0
- package/jest.config.cjs +23 -0
- package/package.json +61 -36
- package/prebuilds/darwin-arm64/@photostructure+fs-metadata.glibc.node +0 -0
- package/prebuilds/darwin-x64/@photostructure+fs-metadata.glibc.node +0 -0
- package/prebuilds/linux-arm64/@photostructure+fs-metadata.glibc.node +0 -0
- package/prebuilds/linux-arm64/@photostructure+fs-metadata.musl.node +0 -0
- package/prebuilds/linux-x64/@photostructure+fs-metadata.glibc.node +0 -0
- package/prebuilds/linux-x64/@photostructure+fs-metadata.musl.node +0 -0
- package/prebuilds/win32-arm64/@photostructure+fs-metadata.glibc.node +0 -0
- package/prebuilds/win32-x64/@photostructure+fs-metadata.glibc.node +0 -0
- package/scripts/check-memory.ts +186 -0
- package/scripts/clang-tidy.ts +690 -99
- package/scripts/install.cjs +42 -0
- package/scripts/is-platform.mjs +1 -1
- package/scripts/macos-asan.sh +155 -0
- package/scripts/post-build.mjs +3 -3
- package/scripts/prebuild-linux-glibc.sh +12 -1
- package/scripts/prebuildify-wrapper.ts +77 -0
- package/scripts/precommit.ts +45 -20
- package/scripts/sanitizers-test.sh +1 -1
- package/src/common/volume_metadata.h +6 -0
- package/src/darwin/hidden.cpp +73 -25
- package/src/darwin/path_security.h +149 -0
- package/src/darwin/raii_utils.h +104 -4
- package/src/darwin/volume_metadata.cpp +132 -58
- package/src/darwin/volume_mount_points.cpp +80 -47
- package/src/hidden.ts +36 -13
- package/src/linux/gio_mount_points.cpp +17 -18
- package/src/linux/gio_utils.cpp +92 -37
- package/src/linux/gio_utils.h +11 -5
- package/src/linux/gio_volume_metadata.cpp +111 -48
- package/src/linux/volume_metadata.cpp +67 -4
- package/src/object.ts +1 -0
- package/src/options.ts +6 -0
- package/src/path.ts +11 -0
- package/src/remote_info.ts +5 -3
- package/src/stack_path.ts +8 -6
- package/src/string_enum.ts +1 -0
- package/src/test-utils/memory-test-core.ts +336 -0
- package/src/test-utils/memory-test-runner.ts +108 -0
- package/src/test-utils/platform.ts +46 -1
- package/src/test-utils/worker-thread-helper.cjs +154 -27
- package/src/types/native_bindings.ts +1 -1
- package/src/types/options.ts +6 -0
- package/src/windows/drive_status.h +133 -163
- package/src/windows/error_utils.h +54 -3
- package/src/windows/fs_meta.h +1 -1
- package/src/windows/hidden.cpp +60 -43
- package/src/windows/security_utils.h +250 -0
- package/src/windows/string.h +68 -11
- package/src/windows/system_volume.h +1 -1
- package/src/windows/thread_pool.h +206 -0
- package/src/windows/volume_metadata.cpp +11 -6
- package/src/windows/volume_mount_points.cpp +8 -7
- package/src/windows/windows_arch.h +39 -0
- package/scripts/check-memory.mjs +0 -123
package/CHANGELOG.md
CHANGED
|
@@ -14,7 +14,13 @@ Fixed for any bug fixes.
|
|
|
14
14
|
Security in case of vulnerabilities.
|
|
15
15
|
-->
|
|
16
16
|
|
|
17
|
-
##
|
|
17
|
+
## 0.7.1 - 2025-10-29
|
|
18
|
+
|
|
19
|
+
- Audit and address [several resource handling issues](./doc/SECURITY_AUDIT_2025.md)
|
|
20
|
+
- Added support for Node.js v25
|
|
21
|
+
- Updated dev dependencies
|
|
22
|
+
|
|
23
|
+
## 0.6.0 - 2025-06-09
|
|
18
24
|
|
|
19
25
|
### Added
|
|
20
26
|
|
package/CLAUDE.md
CHANGED
|
@@ -4,242 +4,151 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|
|
4
4
|
|
|
5
5
|
## Project Overview
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
### Key Features
|
|
10
|
-
- Cross-platform support: Windows 10+ (x64), macOS 14+, Ubuntu 22+ (x64, arm64)
|
|
11
|
-
- Lists all mounted volumes/drives
|
|
12
|
-
- Gets detailed volume metadata (size, usage, filesystem type, etc.)
|
|
13
|
-
- Hidden file/directory attribute support (get/set)
|
|
14
|
-
- Non-blocking async native implementations
|
|
15
|
-
- Timeout handling for unresponsive network volumes
|
|
16
|
-
- ESM and CJS module support
|
|
17
|
-
- Full TypeScript type definitions
|
|
18
|
-
- Worker threads support with proper context isolation
|
|
19
|
-
|
|
20
|
-
### Platform-Specific Notes
|
|
21
|
-
- **Linux**: Optional GIO/GVfs mount support via Gnome libraries
|
|
22
|
-
- **Windows**: Uses separate threads per mountpoint for health checks to handle blocked system calls
|
|
23
|
-
- **System Volumes**: Each platform handles system volumes differently; the library uses heuristics to identify them
|
|
24
|
-
|
|
25
|
-
## Architecture Overview
|
|
26
|
-
|
|
27
|
-
### Core Structure
|
|
28
|
-
- **Native binding layer** (`src/binding.cpp`): Node-API v9 bridge between JavaScript and platform-specific implementations
|
|
29
|
-
- **Platform abstractions** in `src/common/`: Shared C++ interfaces for cross-platform functionality
|
|
30
|
-
- **Platform implementations**:
|
|
31
|
-
- `src/darwin/`: macOS-specific code using Core Foundation APIs
|
|
32
|
-
- `src/linux/`: Linux-specific code with optional GIO support for GNOME/GVfs
|
|
33
|
-
- `src/windows/`: Windows-specific code using Win32 APIs
|
|
34
|
-
|
|
35
|
-
### Key Features
|
|
36
|
-
- **Volume Metadata**: Retrieves filesystem information (mount points, disk usage, health status)
|
|
37
|
-
- **Hidden File Support**: Cross-platform hidden file detection and manipulation
|
|
38
|
-
- **Async Operations**: All native operations use Worker threads to avoid blocking
|
|
39
|
-
|
|
40
|
-
### Build System
|
|
41
|
-
- Uses `node-gyp` for native compilation
|
|
42
|
-
- Conditionally enables GIO support on Linux via `scripts/configure.mjs`
|
|
43
|
-
- Provides prebuilt binaries via `prebuildify` for common platforms
|
|
44
|
-
- Supports both ESM and CJS module formats
|
|
7
|
+
@photostructure/fs-metadata - Cross-platform native Node.js module for filesystem metadata retrieval.
|
|
45
8
|
|
|
46
|
-
###
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
9
|
+
### Directory Structure
|
|
10
|
+
|
|
11
|
+
- `src/` - Source code (TypeScript and C++)
|
|
12
|
+
- `dist/` - Compiled JavaScript output (gitignored)
|
|
13
|
+
- `doc/` - Static documentation (manually written, checked into git)
|
|
14
|
+
- `build/` - All build artifacts (gitignored)
|
|
15
|
+
- `build/docs/` - Generated API documentation from TypeDoc (deployed to GitHub Pages)
|
|
16
|
+
- `scripts/` - Build and utility scripts
|
|
17
|
+
- `prebuilds/` - Prebuilt native binaries for different platforms
|
|
18
|
+
|
|
19
|
+
### Script Preferences
|
|
20
|
+
|
|
21
|
+
**Always** use TypeScript (`.ts`) scripts executed with `tsx` instead of:
|
|
22
|
+
|
|
23
|
+
- `.js` scripts (require compilation or older Node.js syntax)
|
|
24
|
+
- `.mjs` scripts (ESM-only, compatibility issues)
|
|
25
|
+
- `.cjs` scripts (CommonJS-only, less type safety)
|
|
51
26
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
- Memory leak testing with garbage collection monitoring
|
|
56
|
-
- Coverage thresholds: 80% for all metrics
|
|
27
|
+
TypeScript with tsx provides type safety, modern syntax, and seamless execution.
|
|
28
|
+
|
|
29
|
+
## Critical Knowledge
|
|
57
30
|
|
|
58
31
|
### Testing File System Metadata
|
|
59
|
-
- **Important**: File system metadata like `available` space, `used` space, and other dynamic properties change continuously as other processes run on the machine
|
|
60
|
-
- Tests should **never** expect exact equality for these values between multiple calls
|
|
61
|
-
- **Do not** make range assertions (e.g., `available > 0` or `used < size`) because:
|
|
62
|
-
- Files can be created or deleted between calls (potentially gigabytes)
|
|
63
|
-
- The changes can be dramatic and unpredictable
|
|
64
|
-
- Instead, for dynamic metadata:
|
|
65
|
-
- Only verify the value exists and has the correct type
|
|
66
|
-
- Use `typeof result.available === 'number'` rather than range checks
|
|
67
|
-
- Focus on testing static properties (e.g., `size`, `mountFrom`, `fstype`) for exact equality
|
|
68
|
-
- Consider using snapshot testing only for stable properties
|
|
69
|
-
|
|
70
|
-
### Timeout Handling
|
|
71
|
-
- Default timeout for volume operations to handle unresponsive network mounts
|
|
72
|
-
- Windows uses separate threads per mountpoint for health checks
|
|
73
|
-
- Configurable via `Options` interface
|
|
74
|
-
|
|
75
|
-
### Debug Logging
|
|
76
|
-
- Enable with `NODE_DEBUG=fs-meta` or `NODE_DEBUG=photostructure:fs-metadata`
|
|
77
|
-
- Debug messages from both JavaScript and native code are sent to `stderr`
|
|
78
|
-
- Uses native Node.js debuglog for determining if logging is enabled
|
|
79
32
|
|
|
80
|
-
|
|
33
|
+
**Never** expect exact equality for dynamic values (`available`, `used`) between calls. Only verify:
|
|
81
34
|
|
|
82
|
-
|
|
35
|
+
- Value exists and has correct type: `typeof result.available === 'number'`
|
|
36
|
+
- Test static properties (`size`, `mountFrom`, `fstype`) for exact equality
|
|
37
|
+
- Avoid range assertions (`available > 0`) - file changes can be dramatic
|
|
83
38
|
|
|
84
|
-
###
|
|
85
|
-
- Repository secrets must be configured:
|
|
86
|
-
- `NPM_TOKEN`: Authentication token for npm publishing
|
|
87
|
-
- `GPG_PRIVATE_KEY`: ASCII-armored GPG private key for signing commits
|
|
88
|
-
- `GPG_PASSPHRASE`: Passphrase for the GPG key (if applicable)
|
|
39
|
+
### Cross-Module Compatibility
|
|
89
40
|
|
|
90
|
-
|
|
91
|
-
1. Trigger via GitHub Actions workflow dispatch with version type (patch/minor/major)
|
|
92
|
-
2. Builds all prebuilds for supported platforms
|
|
93
|
-
3. Runs comprehensive test suite across platforms
|
|
94
|
-
4. Uses `npm version` to bump version and create signed git tags
|
|
95
|
-
5. Publishes to npm registry
|
|
96
|
-
6. Creates GitHub release with auto-generated notes
|
|
97
|
-
7. All commits and tags are GPG signed for verification
|
|
41
|
+
Use `_dirname()` from `./dirname` instead of `__dirname` - works in both CommonJS and ESM contexts.
|
|
98
42
|
|
|
99
|
-
###
|
|
100
|
-
```bash
|
|
101
|
-
npm run prepare-release
|
|
102
|
-
git config commit.gpgsign true
|
|
103
|
-
npm version patch|minor|major
|
|
104
|
-
npm publish
|
|
105
|
-
git push origin main --follow-tags
|
|
106
|
-
```
|
|
43
|
+
### Node.js Version Compatibility
|
|
107
44
|
|
|
108
|
-
|
|
45
|
+
Jest 30 doesn't support Node.js 23. Use Node.js 20, 22, or 24.
|
|
109
46
|
|
|
110
|
-
|
|
111
|
-
import { getVolumeMountPoints, getVolumeMetadata } from "@photostructure/fs-metadata";
|
|
47
|
+
## Windows-Specific Issues
|
|
112
48
|
|
|
113
|
-
|
|
114
|
-
const mountPoints = await getVolumeMountPoints();
|
|
115
|
-
console.dir({ mountPoints });
|
|
49
|
+
### Windows CI Jest Worker Failures
|
|
116
50
|
|
|
117
|
-
|
|
118
|
-
const volumeMetadata = await getVolumeMetadata(mountPoints[0]);
|
|
119
|
-
console.dir({ volumeMetadata });
|
|
51
|
+
**Problem**: Jest worker processes fail on Windows CI environments (both x64 and ARM64) with "Jest worker encountered 4 child process exceptions".
|
|
120
52
|
|
|
121
|
-
|
|
122
|
-
import { isHidden } from "@photostructure/fs-metadata";
|
|
123
|
-
const hidden = await isHidden("/path/to/file");
|
|
124
|
-
```
|
|
53
|
+
**Solution for Memory Tests**:
|
|
125
54
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
Based on analysis of recent test failures, here are critical patterns to avoid flaky tests:
|
|
129
|
-
|
|
130
|
-
### 1. Benchmark and Performance Tests
|
|
131
|
-
- **Problem**: "Cannot log after tests are done" errors in worker_threads.test.ts
|
|
132
|
-
- **Solution**:
|
|
133
|
-
- Always await all async operations before test completion
|
|
134
|
-
- Use proper test lifecycle hooks (afterEach/afterAll) for cleanup
|
|
135
|
-
- Avoid console.log in async contexts without proper synchronization
|
|
136
|
-
- Consider using test.concurrent with explicit done() callbacks
|
|
137
|
-
|
|
138
|
-
### 2. Alpine Linux ARM64 Issues
|
|
139
|
-
- **Problem**: Tests timeout on emulated Alpine ARM64 environments
|
|
140
|
-
- **Solution**:
|
|
141
|
-
- Skip process-spawning tests on Alpine ARM64 (`if (isAlpine && isARM64)`)
|
|
142
|
-
- Use increased timeout multipliers (20x) for emulated environments
|
|
143
|
-
- Detect emulation via `/proc/cpuinfo` or environment checks
|
|
144
|
-
- Consider separate test suites for native vs emulated environments
|
|
145
|
-
|
|
146
|
-
### 3. Worker Thread Management
|
|
147
|
-
- **Problem**: Race conditions in concurrent worker operations
|
|
148
|
-
- **Solution**:
|
|
149
|
-
- Implement proper worker pool management with size limits
|
|
150
|
-
- Use Promise.allSettled() instead of Promise.all() for parallel operations
|
|
151
|
-
- Add explicit cleanup in test teardown to terminate all workers
|
|
152
|
-
- Set reasonable concurrency limits based on environment (CPU cores)
|
|
153
|
-
|
|
154
|
-
### 4. Timeout Test Reliability
|
|
155
|
-
- **Problem**: Timeout tests fail due to timing precision issues
|
|
156
|
-
- **Solution**:
|
|
157
|
-
- Never use exact timing assertions (e.g., expect 100ms)
|
|
158
|
-
- Use ranges with adequate margins (e.g., 90-110ms)
|
|
159
|
-
- Account for CI environment variability (slower machines)
|
|
160
|
-
- Consider mocking timers for deterministic behavior
|
|
161
|
-
|
|
162
|
-
### 5. File System Operations
|
|
163
|
-
- **Problem**: ENOENT errors for test directories, permission issues
|
|
164
|
-
- **Solution**:
|
|
165
|
-
- Always use unique temporary directories per test
|
|
166
|
-
- Clean up test artifacts in afterEach hooks
|
|
167
|
-
- Check directory existence before operations
|
|
168
|
-
- Handle platform-specific path separators
|
|
169
|
-
|
|
170
|
-
### 6. Memory and Resource Leaks
|
|
171
|
-
- **Problem**: Tests don't properly clean up resources
|
|
172
|
-
- **Solution**:
|
|
173
|
-
- Explicitly close all file handles, network connections
|
|
174
|
-
- Use try-finally blocks for resource cleanup
|
|
175
|
-
- Monitor memory usage in long-running tests
|
|
176
|
-
- Implement proper garbage collection triggers
|
|
177
|
-
|
|
178
|
-
### 7. Platform-Specific Failures
|
|
179
|
-
- **Problem**: Different behavior across Windows/macOS/Linux
|
|
180
|
-
- **Solution**:
|
|
181
|
-
- Use platform detection helpers consistently
|
|
182
|
-
- Skip platform-specific tests appropriately
|
|
183
|
-
- Account for filesystem differences (case sensitivity, path formats)
|
|
184
|
-
- Test with platform-specific CI matrices
|
|
185
|
-
|
|
186
|
-
### 8. Jest Configuration
|
|
187
|
-
- **Problem**: Tests interfere with each other
|
|
188
|
-
- **Solution**:
|
|
189
|
-
- Use `--runInBand` for tests with shared resources
|
|
190
|
-
- Clear module cache between tests when needed
|
|
191
|
-
- Isolate tests that spawn processes
|
|
192
|
-
- Configure proper test timeouts per environment
|
|
193
|
-
|
|
194
|
-
### Async Cleanup Anti-Patterns
|
|
195
|
-
|
|
196
|
-
**IMPORTANT**: The following approaches are NOT valid solutions for async cleanup issues:
|
|
55
|
+
Memory tests now use a standalone TypeScript runner (`src/test-utils/memory-test-runner.ts`) that bypasses Jest entirely on all platforms. This provides more accurate memory measurements without Jest overhead and avoids worker process issues.
|
|
197
56
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
57
|
+
- Run full memory check suite (includes native tools): `npm run check:memory`
|
|
58
|
+
- Memory test logic is in `src/test-utils/memory-test-core.ts`
|
|
201
59
|
|
|
202
|
-
|
|
203
|
-
if (global.gc) {
|
|
204
|
-
global.gc();
|
|
205
|
-
}
|
|
60
|
+
**Workaround for Other Tests**:
|
|
206
61
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
62
|
+
1. Jest is configured to use single worker mode (`maxWorkers: 1`) for all Windows CI environments
|
|
63
|
+
2. Tests that stress worker threads or concurrency are skipped on Windows CI using `describeSkipWindowsCI` or `describePlatformStable`:
|
|
64
|
+
|
|
65
|
+
- `worker_threads.test.ts` - Worker thread integration tests
|
|
66
|
+
- `thread_safety.test.ts` - Concurrent operations stress tests
|
|
67
|
+
- `windows-memory-check.test.ts` - Memory leak detection (Windows only)
|
|
68
|
+
- `windows-resource-security.test.ts` - Resource handle leak tests (Windows only)
|
|
69
|
+
|
|
70
|
+
**Note**: These tests pass locally but fail in CI. The native module loads correctly, but Jest's worker process management has fundamental incompatibilities with these specific tests on GitHub Actions Windows runners.
|
|
212
71
|
|
|
213
|
-
|
|
72
|
+
### Build Architecture Issue
|
|
214
73
|
|
|
215
|
-
|
|
216
|
-
2. **Forcing GC** should never be required for correct behavior. If your code depends on GC for correctness, it has a fundamental design flaw.
|
|
217
|
-
3. **setImmediate/nextTick delays** in cleanup hooks don't fix the root cause - they just paper over the real issue.
|
|
218
|
-
4. These approaches mask the real problem instead of fixing it.
|
|
74
|
+
**Problem**: "No Target Architecture" error from Windows SDK headers when building with node-gyp/prebuildify.
|
|
219
75
|
|
|
220
|
-
**
|
|
76
|
+
**Solution**: Use `scripts/prebuildify-wrapper.ts` which sets the `CL` environment variable with architecture defines:
|
|
221
77
|
|
|
222
|
-
-
|
|
223
|
-
-
|
|
224
|
-
- Testing timeout behavior itself
|
|
78
|
+
- For x64: `CL=/D_M_X64 /D_WIN64 /D_AMD64_`
|
|
79
|
+
- For ARM64: `CL=/D_M_ARM64 /D_WIN64`
|
|
225
80
|
|
|
226
|
-
|
|
81
|
+
**Why This is Necessary**:
|
|
227
82
|
|
|
228
|
-
|
|
83
|
+
- Prebuildify doesn't properly pass architecture defines from binding.gyp conditions
|
|
84
|
+
- The Windows SDK requires these macros before including `<windows.h>`
|
|
85
|
+
- Projects like node-sqlite avoid this by not using Windows headers directly
|
|
229
86
|
|
|
230
|
-
|
|
231
|
-
2. Ensure all database connections are properly closed
|
|
232
|
-
3. Ensure all file handles are closed
|
|
233
|
-
4. Cancel or await all pending async operations
|
|
234
|
-
5. Use proper resource management patterns (RAII, try-finally, using statements)
|
|
87
|
+
**Why Other Approaches Failed**:
|
|
235
88
|
|
|
236
|
-
|
|
89
|
+
- **Source file defines**: Would hardcode x64 defines, breaking ARM64 builds
|
|
90
|
+
- **windows_compat.h wrapper**: Can't distinguish x64 from ARM64 at compile time
|
|
91
|
+
- **binding.gyp conditions**: Not evaluated properly by prebuildify
|
|
92
|
+
- **msvs_settings defines**: Not passed through to the compiler
|
|
237
93
|
|
|
238
|
-
|
|
94
|
+
### Memory Testing Limitations
|
|
239
95
|
|
|
240
|
-
|
|
96
|
+
Traditional Windows tools **do not work** with Node.js native modules:
|
|
241
97
|
|
|
242
|
-
**
|
|
98
|
+
- **Dr. Memory**: Fails with "Unable to load client library: ucrtbase.dll"
|
|
99
|
+
- **Debug CRT builds**: Cannot be loaded by Node.js (missing debug runtime + UNC path issues)
|
|
100
|
+
- **Visual Leak Detector**: Requires debug builds which don't work
|
|
101
|
+
- **Application Verifier**: Cannot hook into Node.js memory management
|
|
102
|
+
|
|
103
|
+
Use JavaScript-based memory testing (`src/windows-memory-check.test.ts`) instead.
|
|
104
|
+
|
|
105
|
+
### Static Analysis (clang-tidy) Limitations
|
|
106
|
+
|
|
107
|
+
**clang-tidy on Windows** has limited effectiveness due to MSVC header incompatibility:
|
|
108
|
+
|
|
109
|
+
- Generates many false errors about missing std namespace members
|
|
110
|
+
- Still provides valuable warnings about your code
|
|
111
|
+
- See `doc/windows-clang-tidy.md` for details
|
|
112
|
+
- Consider using Visual Studio Code Analysis as an alternative
|
|
113
|
+
|
|
114
|
+
### WSL Development
|
|
115
|
+
|
|
116
|
+
Run Windows commands from WSL:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
cmd.exe /c "cd C:\\Users\\matth\\src\\fs-metadata && npm test"
|
|
120
|
+
# Or create helper: echo 'cmd.exe /c "cd C:\\Users\\matth\\src\\fs-metadata && $@"' > ~/bin/win-run
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Memory Leak Detection
|
|
124
|
+
|
|
125
|
+
Run `npm run check:memory` for comprehensive platform-specific testing:
|
|
126
|
+
|
|
127
|
+
- **All platforms**: JavaScript memory tests with GC triggers
|
|
128
|
+
- **Windows**: Handle count monitoring via `process.report`
|
|
129
|
+
- **Linux**: Valgrind + AddressSanitizer/LeakSanitizer
|
|
130
|
+
- **macOS**: AddressSanitizer (may fail due to SIP - expected)
|
|
131
|
+
|
|
132
|
+
## CI/CD Test Reliability
|
|
133
|
+
|
|
134
|
+
### Critical Anti-Patterns
|
|
135
|
+
|
|
136
|
+
**Never** use these to "fix" async issues:
|
|
137
|
+
|
|
138
|
+
```javascript
|
|
139
|
+
// BAD: Arbitrary timeouts
|
|
140
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
141
|
+
// BAD: Forcing GC
|
|
142
|
+
if (global.gc) global.gc();
|
|
143
|
+
// BAD: setImmediate in afterAll
|
|
144
|
+
afterAll(async () => {
|
|
145
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
146
|
+
});
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Windows Directory Cleanup
|
|
150
|
+
|
|
151
|
+
Always use retry logic:
|
|
243
152
|
|
|
244
153
|
```typescript
|
|
245
154
|
await fsp.rm(tempDir, {
|
|
@@ -250,125 +159,42 @@ await fsp.rm(tempDir, {
|
|
|
250
159
|
});
|
|
251
160
|
```
|
|
252
161
|
|
|
253
|
-
|
|
162
|
+
### Platform Performance Multipliers
|
|
254
163
|
|
|
255
|
-
|
|
164
|
+
- Alpine Linux (musl): 2x slower
|
|
165
|
+
- ARM64 emulation: 5x slower
|
|
166
|
+
- Windows processes: 4x slower
|
|
167
|
+
- macOS VMs: 4x slower
|
|
256
168
|
|
|
257
|
-
|
|
169
|
+
### Multi-Process Synchronization
|
|
258
170
|
|
|
259
|
-
|
|
171
|
+
Use explicit signals:
|
|
260
172
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
- macOS VMs are 4x slower
|
|
265
|
-
- CI environments have resource constraints
|
|
266
|
-
|
|
267
|
-
**Solutions**:
|
|
268
|
-
|
|
269
|
-
```typescript
|
|
270
|
-
// DON'T: Use fixed timeouts
|
|
271
|
-
test("my test", async () => {
|
|
272
|
-
// Test code
|
|
273
|
-
}, 10000);
|
|
274
|
-
|
|
275
|
-
// DO: Use adaptive timeouts based on environment
|
|
276
|
-
import { getTestTimeout } from "./test-utils/test-timeout-config";
|
|
277
|
-
|
|
278
|
-
test(
|
|
279
|
-
"my test",
|
|
280
|
-
async () => {
|
|
281
|
-
// Test code
|
|
282
|
-
},
|
|
283
|
-
getTestTimeout(10000),
|
|
284
|
-
);
|
|
285
|
-
|
|
286
|
-
// DO: Account for platform timing differences
|
|
287
|
-
const timingMultiplier = process.platform === "win32" ? 4 :
|
|
288
|
-
process.platform === "darwin" ? 4 :
|
|
289
|
-
process.env.CI ? 2 : 1;
|
|
173
|
+
```javascript
|
|
174
|
+
console.log("READY"); // Signal readiness
|
|
175
|
+
console.log("RESULT:" + outcome); // Signal result
|
|
290
176
|
```
|
|
291
177
|
|
|
292
|
-
|
|
178
|
+
## Release Process
|
|
293
179
|
|
|
294
|
-
|
|
180
|
+
Requires repository secrets:
|
|
295
181
|
|
|
296
|
-
|
|
182
|
+
- `NPM_TOKEN`: npm authentication
|
|
183
|
+
- `GPG_PRIVATE_KEY`: ASCII-armored GPG key
|
|
184
|
+
- `GPG_PASSPHRASE`: GPG passphrase
|
|
297
185
|
|
|
298
|
-
|
|
186
|
+
Automated via GitHub Actions workflow dispatch or manual:
|
|
299
187
|
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
// DO: Use explicit synchronization signals
|
|
307
|
-
const script = `
|
|
308
|
-
// Setup code
|
|
309
|
-
console.log("READY"); // Signal readiness
|
|
310
|
-
// Main test logic
|
|
311
|
-
console.log("RESULT:" + outcome);
|
|
312
|
-
`;
|
|
313
|
-
|
|
314
|
-
const proc = spawn(process.execPath, ["-e", script]);
|
|
315
|
-
await waitForOutput(proc, "READY"); // Wait for process to be ready
|
|
316
|
-
const result = await waitForOutput(proc, "RESULT:");
|
|
317
|
-
expect(result.split(":")[1]).toBe("expected_outcome");
|
|
188
|
+
```bash
|
|
189
|
+
npm run prepare-release
|
|
190
|
+
git config commit.gpgsign true
|
|
191
|
+
npm version patch|minor|major
|
|
192
|
+
npm publish
|
|
193
|
+
git push origin main --follow-tags
|
|
318
194
|
```
|
|
319
195
|
|
|
320
|
-
|
|
196
|
+
## General guidance
|
|
321
197
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
**Solution**: Implement robust condition waiting with platform-aware timing:
|
|
325
|
-
|
|
326
|
-
```typescript
|
|
327
|
-
async function waitForCondition(
|
|
328
|
-
check: () => boolean | Promise<boolean>,
|
|
329
|
-
options: {
|
|
330
|
-
maxAttempts?: number;
|
|
331
|
-
delay?: number;
|
|
332
|
-
timeoutMs?: number;
|
|
333
|
-
} = {}
|
|
334
|
-
) {
|
|
335
|
-
const {
|
|
336
|
-
maxAttempts = 50,
|
|
337
|
-
delay = 100,
|
|
338
|
-
timeoutMs = 30000
|
|
339
|
-
} = options;
|
|
340
|
-
|
|
341
|
-
const startTime = Date.now();
|
|
342
|
-
|
|
343
|
-
for (let i = 0; i < maxAttempts; i++) {
|
|
344
|
-
if (Date.now() - startTime > timeoutMs) {
|
|
345
|
-
throw new Error(`Condition not met within ${timeoutMs}ms`);
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
if (await check()) return true;
|
|
349
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
return false;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
// Usage example
|
|
356
|
-
await waitForCondition(
|
|
357
|
-
() => fs.existsSync(expectedFile),
|
|
358
|
-
{ timeoutMs: getTestTimeout(10000) }
|
|
359
|
-
);
|
|
360
|
-
```
|
|
198
|
+
Never do inline imports like `const { mkdirSync } = await import("node:fs");` -- just use standard imports.
|
|
361
199
|
|
|
362
|
-
|
|
363
|
-
1. **Always clean up**: Resources, timers, workers, file handles
|
|
364
|
-
2. **Never assume timing**: Use ranges and adaptive timeouts, not exact values
|
|
365
|
-
3. **Isolate tests**: Each test should be independent
|
|
366
|
-
4. **Platform awareness**: Skip tests that can't work on certain platforms
|
|
367
|
-
5. **Proper async handling**: Always await or return promises
|
|
368
|
-
6. **Resource limits**: Don't spawn unlimited workers/processes
|
|
369
|
-
7. **Environment detection**: Adjust behavior for CI vs local
|
|
370
|
-
8. **Deterministic tests**: Mock external dependencies when possible
|
|
371
|
-
9. **Explicit synchronization**: Use signals for multi-process coordination
|
|
372
|
-
10. **Robust waiting**: Use condition-based waiting instead of arbitrary timeouts
|
|
373
|
-
11. **Windows compatibility**: Use retry logic for file operations on Windows
|
|
374
|
-
12. **Anti-pattern awareness**: Avoid masking problems with timeouts or forced GC
|
|
200
|
+
Never include claude code messages in git commits
|
package/CODE_OF_CONDUCT.md
CHANGED
|
@@ -17,23 +17,23 @@ diverse, inclusive, and healthy community.
|
|
|
17
17
|
Examples of behavior that contributes to a positive environment for our
|
|
18
18
|
community include:
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
- Demonstrating empathy and kindness toward other people
|
|
21
|
+
- Being respectful of differing opinions, viewpoints, and experiences
|
|
22
|
+
- Giving and gracefully accepting constructive feedback
|
|
23
|
+
- Accepting responsibility and apologizing to those affected by our mistakes,
|
|
24
24
|
and learning from the experience
|
|
25
|
-
|
|
25
|
+
- Focusing on what is best not just for us as individuals, but for the
|
|
26
26
|
overall community
|
|
27
27
|
|
|
28
28
|
Examples of unacceptable behavior include:
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
- The use of sexualized language or imagery, and sexual attention or
|
|
31
31
|
advances of any kind
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
- Trolling, insulting or derogatory comments, and personal or political attacks
|
|
33
|
+
- Public or private harassment
|
|
34
|
+
- Publishing others' private information, such as a physical or email
|
|
35
35
|
address, without their explicit permission
|
|
36
|
-
|
|
36
|
+
- Other conduct which could reasonably be considered inappropriate in a
|
|
37
37
|
professional setting
|
|
38
38
|
|
|
39
39
|
## Enforcement Responsibilities
|
|
@@ -106,7 +106,7 @@ Violating these terms may lead to a permanent ban.
|
|
|
106
106
|
### 4. Permanent Ban
|
|
107
107
|
|
|
108
108
|
**Community Impact**: Demonstrating a pattern of violation of community
|
|
109
|
-
standards, including sustained inappropriate behavior,
|
|
109
|
+
standards, including sustained inappropriate behavior, harassment of an
|
|
110
110
|
individual, or aggression toward or disparagement of classes of individuals.
|
|
111
111
|
|
|
112
112
|
**Consequence**: A permanent ban from any sort of public interaction within
|
package/CONTRIBUTING.md
CHANGED
|
@@ -26,7 +26,7 @@ Install the Xcode Command Line Tools, and then
|
|
|
26
26
|
|
|
27
27
|
### On Ubuntu/Debian
|
|
28
28
|
|
|
29
|
-
sudo apt-get install build-essential clang-format libglib2.0-dev libblkid-dev uuid-dev
|
|
29
|
+
sudo apt-get install bear build-essential clang-format libglib2.0-dev libblkid-dev uuid-dev
|
|
30
30
|
|
|
31
31
|
## Before submitting your PR
|
|
32
32
|
|