Adopt @parcel/watcher@2.0.7 (#169553)

* watcher - add debounce logic to parcel too

* 🆙 `@parcel/watcher: 2.0.7`

* bring back dispose

* 💄

* more cleanup

* tests

* 💄

* same debounces
This commit is contained in:
Benjamin Pasero 2022-12-20 09:34:40 +01:00 committed by GitHub
parent fef6e86202
commit 430e35b22c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 166 additions and 142 deletions

View file

@ -62,7 +62,7 @@
"dependencies": {
"@microsoft/1ds-core-js": "^3.2.2",
"@microsoft/1ds-post-js": "^3.2.2",
"@parcel/watcher": "2.0.5",
"@parcel/watcher": "2.0.7",
"@vscode/iconv-lite-umd": "0.7.0",
"@vscode/ripgrep": "^1.14.2",
"@vscode/sqlite3": "5.1.2-vscode",

View file

@ -5,7 +5,7 @@
"dependencies": {
"@microsoft/1ds-core-js": "^3.2.2",
"@microsoft/1ds-post-js": "^3.2.2",
"@parcel/watcher": "2.0.5",
"@parcel/watcher": "2.0.7",
"@vscode/iconv-lite-umd": "0.7.0",
"@vscode/ripgrep": "^1.14.2",
"@vscode/vscode-languagedetection": "1.0.21",

View file

@ -38,10 +38,10 @@
resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc"
integrity sha512-D1Oivw1A4bIXhzBIy3/BBPn3p2On+kpO2NiYt9shICDK7L/w+cR6FFBUsBZ05l6iqzTeL+Jm8lAYn0g6G7DmDg==
"@parcel/watcher@2.0.5":
version "2.0.5"
resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.0.5.tgz#f913a54e1601b0aac972803829b0eece48de215b"
integrity sha512-x0hUbjv891omnkcHD7ZOhiyyUqUUR6MNjq89JhEI3BxppeKWAm6NPQsqqRrAkCJBogdT/o/My21sXtTI9rJIsw==
"@parcel/watcher@2.0.7":
version "2.0.7"
resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.0.7.tgz#c95fe1370e8c6237cb9729c9c075264acc7e21a5"
integrity sha512-gc3hoS6e+2XdIQ4HHljDB1l0Yx2EWh/sBBtCEFNKGSMlwASWeAQsOY/fPbxOBcZ/pg0jBh4Ga+4xHlZc4faAEQ==
dependencies:
node-addon-api "^3.2.1"
node-gyp-build "^4.3.0"

View file

@ -875,6 +875,13 @@ export class RunOnceScheduler implements IDisposable {
return this.timeoutToken !== -1;
}
flush(): void {
if (this.isScheduled()) {
this.cancel();
this.doRun();
}
}
private onTimeout() {
this.timeoutToken = -1;
if (this.runner) {
@ -961,6 +968,7 @@ export class ProcessTimeRunOnceScheduler {
}
export class RunOnceWorker<T> extends RunOnceScheduler {
private units: T[] = [];
constructor(runner: (units: T[]) => void, timeout: number) {

View file

@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { watch } from 'fs';
import { ThrottledDelayer, ThrottledWorker } from 'vs/base/common/async';
import { RunOnceWorker, ThrottledWorker } from 'vs/base/common/async';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { isEqualOrParent } from 'vs/base/common/extpath';
import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
@ -26,25 +26,26 @@ export class NodeJSFileWatcherLibrary extends Disposable {
// A delay for collecting file changes from node.js
// before collecting them for coalescing and emitting
// (same delay as Parcel is using)
private static readonly FILE_CHANGES_HANDLER_DELAY = 50;
// Same delay as used for the recursive watcher.
private static readonly FILE_CHANGES_HANDLER_DELAY = 75;
// Reduce likelyhood of spam from file events via throttling.
// These numbers are a bit more aggressive compared to the
// recursive watcher because we can have many individual
// node.js watchers per request.
// (https://github.com/microsoft/vscode/issues/124723)
private readonly throttledFileChangesWorker = new ThrottledWorker<IDiskFileChange>(
private readonly throttledFileChangesEmitter = this._register(new ThrottledWorker<IDiskFileChange>(
{
maxWorkChunkSize: 100, // only process up to 100 changes at once before...
throttleDelay: 200, // ...resting for 200ms until we process events again...
maxBufferedWork: 10000 // ...but never buffering more than 10000 events in memory
},
events => this.onDidFilesChange(events)
);
));
private readonly fileChangesDelayer = this._register(new ThrottledDelayer<void>(NodeJSFileWatcherLibrary.FILE_CHANGES_HANDLER_DELAY));
private fileChangesBuffer: IDiskFileChange[] = [];
// Aggregate file changes over FILE_CHANGES_HANDLER_DELAY
// to coalesce events and reduce spam.
private readonly fileChangesAggregator = this._register(new RunOnceWorker<IDiskFileChange>(events => this.handleFileChanges(events), NodeJSFileWatcherLibrary.FILE_CHANGES_HANDLER_DELAY));
private readonly excludes = parseWatcherPatterns(this.request.path, this.request.excludes);
private readonly includes = this.request.includes ? parseWatcherPatterns(this.request.path, this.request.includes) : undefined;
@ -324,12 +325,13 @@ export class NodeJSFileWatcherLibrary extends Disposable {
// File seems to be really gone, so emit a deleted event and dispose
else {
const eventPromise = this.onFileChange({ path: this.request.path, type: FileChangeType.DELETED }, true /* skip excludes/includes (file is explicitly watched) */);
this.onFileChange({ path: this.request.path, type: FileChangeType.DELETED }, true /* skip excludes/includes (file is explicitly watched) */);
// Important to await the event delivery
// Important to flush the event delivery
// before disposing the watcher, otherwise
// we will loose this event.
await eventPromise;
this.fileChangesAggregator.flush();
this.dispose();
}
}, NodeJSFileWatcherLibrary.FILE_DELETE_HANDLER_DELAY);
@ -358,7 +360,7 @@ export class NodeJSFileWatcherLibrary extends Disposable {
});
}
private async onFileChange(event: IDiskFileChange, skipIncludeExcludeChecks = false): Promise<void> {
private onFileChange(event: IDiskFileChange, skipIncludeExcludeChecks = false): void {
if (this.cts.token.isCancellationRequested) {
return;
}
@ -368,7 +370,7 @@ export class NodeJSFileWatcherLibrary extends Disposable {
this.trace(`${event.type === FileChangeType.ADDED ? '[ADDED]' : event.type === FileChangeType.DELETED ? '[DELETED]' : '[CHANGED]'} ${event.path}`);
}
// Add to buffer unless excluded or not included (not if explicitly disabled)
// Add to aggregator unless excluded or not included (not if explicitly disabled)
if (!skipIncludeExcludeChecks && this.excludes.some(exclude => exclude(event.path))) {
if (this.verboseLogging) {
this.trace(` >> ignored (excluded) ${event.path}`);
@ -378,42 +380,34 @@ export class NodeJSFileWatcherLibrary extends Disposable {
this.trace(` >> ignored (not included) ${event.path}`);
}
} else {
this.fileChangesBuffer.push(event);
this.fileChangesAggregator.work(event);
}
}
// Handle emit through delayer to accommodate for bulk changes and thus reduce spam
try {
await this.fileChangesDelayer.trigger(async () => {
const fileChanges = this.fileChangesBuffer;
this.fileChangesBuffer = [];
private handleFileChanges(fileChanges: IDiskFileChange[]): void {
// Coalesce events: merge events of same kind
const coalescedFileChanges = coalesceEvents(fileChanges);
// Coalesce events: merge events of same kind
const coalescedFileChanges = coalesceEvents(fileChanges);
if (coalescedFileChanges.length > 0) {
if (coalescedFileChanges.length > 0) {
// Logging
if (this.verboseLogging) {
for (const event of coalescedFileChanges) {
this.trace(`>> normalized ${event.type === FileChangeType.ADDED ? '[ADDED]' : event.type === FileChangeType.DELETED ? '[DELETED]' : '[CHANGED]'} ${event.path}`);
}
}
// Broadcast to clients via throttler
const worked = this.throttledFileChangesWorker.work(coalescedFileChanges);
// Logging
if (!worked) {
this.warn(`started ignoring events due to too many file change events at once (incoming: ${coalescedFileChanges.length}, most recent change: ${coalescedFileChanges[0].path}). Use 'files.watcherExclude' setting to exclude folders with lots of changing files (e.g. compilation output).`);
} else {
if (this.throttledFileChangesWorker.pending > 0) {
this.trace(`started throttling events due to large amount of file change events at once (pending: ${this.throttledFileChangesWorker.pending}, most recent change: ${coalescedFileChanges[0].path}). Use 'files.watcherExclude' setting to exclude folders with lots of changing files (e.g. compilation output).`);
}
}
// Logging
if (this.verboseLogging) {
for (const event of coalescedFileChanges) {
this.trace(`>> normalized ${event.type === FileChangeType.ADDED ? '[ADDED]' : event.type === FileChangeType.DELETED ? '[DELETED]' : '[CHANGED]'} ${event.path}`);
}
});
} catch (error) {
// ignore (we are likely disposed and cancelled)
}
// Broadcast to clients via throttled emitter
const worked = this.throttledFileChangesEmitter.work(coalescedFileChanges);
// Logging
if (!worked) {
this.warn(`started ignoring events due to too many file change events at once (incoming: ${coalescedFileChanges.length}, most recent change: ${coalescedFileChanges[0].path}). Use 'files.watcherExclude' setting to exclude folders with lots of changing files (e.g. compilation output).`);
} else {
if (this.throttledFileChangesEmitter.pending > 0) {
this.trace(`started throttling events due to large amount of file change events at once (pending: ${this.throttledFileChangesEmitter.pending}, most recent change: ${coalescedFileChanges[0].path}). Use 'files.watcherExclude' setting to exclude folders with lots of changing files (e.g. compilation output).`);
}
}
}
}

View file

@ -6,7 +6,7 @@
import * as parcelWatcher from '@parcel/watcher';
import { existsSync, statSync, unlinkSync } from 'fs';
import { tmpdir } from 'os';
import { DeferredPromise, RunOnceScheduler, ThrottledWorker } from 'vs/base/common/async';
import { DeferredPromise, RunOnceScheduler, RunOnceWorker, ThrottledWorker } from 'vs/base/common/async';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { toErrorMessage } from 'vs/base/common/errorMessage';
import { Emitter } from 'vs/base/common/event';
@ -88,16 +88,32 @@ export class ParcelWatcher extends Disposable implements IRecursiveWatcher {
protected readonly watchers = new Map<string, IParcelWatcherInstance>();
// A delay for collecting file changes from Parcel
// before collecting them for coalescing and emitting.
// Parcel internally uses 50ms as delay, so we use 75ms,
// to schedule sufficiently after Parcel.
//
// Note: since Parcel 2.0.7, the very first event is
// emitted without delay if no events occured over a
// duration of 500ms. But we always want to aggregate
// events to apply our coleasing logic.
//
private static readonly FILE_CHANGES_HANDLER_DELAY = 75;
// Reduce likelyhood of spam from file events via throttling.
// (https://github.com/microsoft/vscode/issues/124723)
private readonly throttledFileChangesWorker = new ThrottledWorker<IDiskFileChange>(
private readonly throttledFileChangesEmitter = this._register(new ThrottledWorker<IDiskFileChange>(
{
maxWorkChunkSize: 500, // only process up to 500 changes at once before...
throttleDelay: 200, // ...resting for 200ms until we process events again...
maxBufferedWork: 30000 // ...but never buffering more than 30000 events in memory
},
events => this._onDidChangeFile.fire(events)
);
));
// Aggregate file changes over FILE_CHANGES_HANDLER_DELAY
// to coalesce events and reduce duplicate events.
private readonly fileChangesAggregator = this._register(new RunOnceWorker<IDiskFileChange>(events => this.handleParcelEvents(events), ParcelWatcher.FILE_CHANGES_HANDLER_DELAY));
private verboseLogging = false;
private enospcErrorLogged = false;
@ -395,23 +411,14 @@ export class ParcelWatcher extends Disposable implements IRecursiveWatcher {
// Normalize events: handle NFC normalization and symlinks
// It is important to do this before checking for includes
// and excludes to check on the original path.
const { events: normalizedEvents, rootDeleted } = this.normalizeEvents(parcelEvents, watcher.request, realPathDiffers, realPathLength);
this.normalizeEvents(parcelEvents, watcher.request, realPathDiffers, realPathLength);
// Check for excludes
const includedEvents = this.handleExcludeIncludes(normalizedEvents, excludes, includes);
const includedEvents = this.handleExcludeIncludes(parcelEvents, excludes, includes);
// Coalesce events: merge events of same kind
const coalescedEvents = coalesceEvents(includedEvents);
// Filter events: check for specific events we want to exclude
const filteredEvents = this.filterEvents(coalescedEvents, watcher.request, rootDeleted);
// Broadcast to clients
this.emitEvents(filteredEvents);
// Handle root path delete if confirmed from coalesced events
if (rootDeleted && coalescedEvents.some(event => event.path === watcher.request.path && event.type === FileChangeType.DELETED)) {
this.onWatchedPathDeleted(watcher);
// Add to aggregator for later processing
for (const includedEvent of includedEvents) {
this.fileChangesAggregator.work(includedEvent);
}
}
@ -441,6 +448,25 @@ export class ParcelWatcher extends Disposable implements IRecursiveWatcher {
return events;
}
private handleParcelEvents(parcelEvents: IDiskFileChange[]): void {
// Coalesce events: merge events of same kind
const coalescedEvents = coalesceEvents(parcelEvents);
// Filter events: check for specific events we want to exclude
const { events: filteredEvents, deletedRoots } = this.filterEvents(coalescedEvents);
// Broadcast to clients
this.emitEvents(filteredEvents);
// Handle root path deletes
if (deletedRoots) {
for (const deletedRoot of deletedRoots) {
this.onWatchedPathDeleted(deletedRoot);
}
}
}
private emitEvents(events: IDiskFileChange[]): void {
if (events.length === 0) {
return;
@ -454,14 +480,14 @@ export class ParcelWatcher extends Disposable implements IRecursiveWatcher {
}
// Broadcast to clients via throttler
const worked = this.throttledFileChangesWorker.work(events);
const worked = this.throttledFileChangesEmitter.work(events);
// Logging
if (!worked) {
this.warn(`started ignoring events due to too many file change events at once (incoming: ${events.length}, most recent change: ${events[0].path}). Use 'files.watcherExclude' setting to exclude folders with lots of changing files (e.g. compilation output).`);
} else {
if (this.throttledFileChangesWorker.pending > 0) {
this.trace(`started throttling events due to large amount of file change events at once (pending: ${this.throttledFileChangesWorker.pending}, most recent change: ${events[0].path}). Use 'files.watcherExclude' setting to exclude folders with lots of changing files (e.g. compilation output).`);
if (this.throttledFileChangesEmitter.pending > 0) {
this.trace(`started throttling events due to large amount of file change events at once (pending: ${this.throttledFileChangesEmitter.pending}, most recent change: ${events[0].path}). Use 'files.watcherExclude' setting to exclude folders with lots of changing files (e.g. compilation output).`);
}
}
}
@ -496,9 +522,7 @@ export class ParcelWatcher extends Disposable implements IRecursiveWatcher {
return { realPath, realPathDiffers, realPathLength };
}
private normalizeEvents(events: parcelWatcher.Event[], request: IRecursiveWatchRequest, realPathDiffers: boolean, realPathLength: number): { events: parcelWatcher.Event[]; rootDeleted: boolean } {
let rootDeleted = false;
private normalizeEvents(events: parcelWatcher.Event[], request: IRecursiveWatchRequest, realPathDiffers: boolean, realPathLength: number): void {
for (const event of events) {
// Mac uses NFD unicode form on disk, but we want NFC
@ -518,33 +542,33 @@ export class ParcelWatcher extends Disposable implements IRecursiveWatcher {
if (realPathDiffers) {
event.path = request.path + event.path.substr(realPathLength);
}
// Check for root deleted
if (event.path === request.path && event.type === 'delete') {
rootDeleted = true;
}
}
return { events, rootDeleted };
}
private filterEvents(events: IDiskFileChange[], request: IRecursiveWatchRequest, rootDeleted: boolean): IDiskFileChange[] {
if (!rootDeleted) {
return events;
}
private filterEvents(events: IDiskFileChange[]): { events: IDiskFileChange[]; deletedRoots?: Set<IParcelWatcherInstance> } {
const filteredEvents: IDiskFileChange[] = [];
let deletedRoots: Set<IParcelWatcherInstance> | undefined = undefined;
for (const event of events) {
if (event.type === FileChangeType.DELETED && this.watchers.has(event.path)) {
return events.filter(event => {
if (event.path === request.path && event.type === FileChangeType.DELETED) {
// Explicitly exclude changes to root if we have any
// to avoid VS Code closing all opened editors which
// can happen e.g. in case of network connectivity
// issues
// (https://github.com/microsoft/vscode/issues/136673)
return false;
}
return true;
});
if (!deletedRoots) {
deletedRoots = new Set();
}
deletedRoots.add(this.watchers.get(event.path)!);
} else {
filteredEvents.push(event);
}
}
return { events: filteredEvents, deletedRoots };
}
private onWatchedPathDeleted(watcher: IParcelWatcherInstance): void {

View file

@ -64,6 +64,7 @@ import { NodeJSWatcher } from 'vs/platform/files/node/watcher/nodejs/nodejsWatch
setup(async () => {
watcher = new TestNodeJSWatcher();
watcher?.setVerboseLogging(loggingEnabled);
watcher.onDidLogMessage(e => {
if (loggingEnabled) {

View file

@ -13,7 +13,7 @@ import { Promises, RimRafMode } from 'vs/base/node/pfs';
import { flakySuite, getPathFromAmdModule, getRandomTestPath } from 'vs/base/test/node/testUtils';
import { FileChangeType } from 'vs/platform/files/common/files';
import { ParcelWatcher } from 'vs/platform/files/node/watcher/parcel/parcelWatcher';
import { IRecursiveWatchRequest } from 'vs/platform/files/common/watcher';
import { IDiskFileChange, IRecursiveWatchRequest } from 'vs/platform/files/common/watcher';
import { getDriveLetter } from 'vs/base/common/extpath';
import { ltrim } from 'vs/base/common/strings';
@ -66,6 +66,7 @@ import { ltrim } from 'vs/base/common/strings';
setup(async () => {
watcher = new TestParcelWatcher();
watcher.setVerboseLogging(loggingEnabled);
watcher.onDidLogMessage(e => {
if (loggingEnabled) {
@ -105,13 +106,13 @@ import { ltrim } from 'vs/base/common/strings';
}
}
async function awaitEvent(service: TestParcelWatcher, path: string, type: FileChangeType, failOnEventReason?: string): Promise<void> {
async function awaitEvent(service: TestParcelWatcher, path: string, type: FileChangeType, failOnEventReason?: string): Promise<IDiskFileChange[]> {
if (loggingEnabled) {
console.log(`Awaiting change type '${toMsg(type)}' on file '${path}'`);
}
// Await the event
await new Promise<void>((resolve, reject) => {
const res = await new Promise<IDiskFileChange[]>((resolve, reject) => {
const disposable = service.onDidChangeFile(events => {
for (const event of events) {
if (event.path === path && event.type === type) {
@ -119,7 +120,7 @@ import { ltrim } from 'vs/base/common/strings';
if (failOnEventReason) {
reject(new Error(`Unexpected file event: ${failOnEventReason}`));
} else {
setImmediate(() => resolve()); // copied from parcel watcher tests, seems to drop unrelated events on macOS
setImmediate(() => resolve(events)); // copied from parcel watcher tests, seems to drop unrelated events on macOS
}
break;
}
@ -132,6 +133,8 @@ import { ltrim } from 'vs/base/common/strings';
// change event
// Refs: https://github.com/microsoft/vscode/issues/137430
await timeout(1);
return res;
}
function awaitMessage(service: TestParcelWatcher, type: 'trace' | 'warn' | 'error' | 'info' | 'debug'): Promise<void> {
@ -244,26 +247,20 @@ import { ltrim } from 'vs/base/common/strings';
await Promises.writeFile(anotherNewFilePath, 'Hello Another World');
await changeFuture;
// Skip following asserts on macOS where the fs-events service
// does not really give a full guarantee about the correlation
// of an event to a change.
if (!isMacintosh) {
// Read file does not emit event
changeFuture = awaitEvent(watcher, anotherNewFilePath, FileChangeType.UPDATED, 'unexpected-event-from-read-file');
await Promises.readFile(anotherNewFilePath);
await Promise.race([timeout(100), changeFuture]);
// Read file does not emit event
changeFuture = awaitEvent(watcher, anotherNewFilePath, FileChangeType.UPDATED, 'unexpected-event-from-read-file');
await Promises.readFile(anotherNewFilePath);
await Promise.race([timeout(100), changeFuture]);
// Stat file does not emit event
changeFuture = awaitEvent(watcher, anotherNewFilePath, FileChangeType.UPDATED, 'unexpected-event-from-stat');
await Promises.stat(anotherNewFilePath);
await Promise.race([timeout(100), changeFuture]);
// Stat file does not emit event
changeFuture = awaitEvent(watcher, anotherNewFilePath, FileChangeType.UPDATED, 'unexpected-event-from-stat');
await Promises.stat(anotherNewFilePath);
await Promise.race([timeout(100), changeFuture]);
// Stat folder does not emit event
changeFuture = awaitEvent(watcher, copiedFolderpath, FileChangeType.UPDATED, 'unexpected-event-from-stat');
await Promises.stat(copiedFolderpath);
await Promise.race([timeout(100), changeFuture]);
}
// Stat folder does not emit event
changeFuture = awaitEvent(watcher, copiedFolderpath, FileChangeType.UPDATED, 'unexpected-event-from-stat');
await Promises.stat(copiedFolderpath);
await Promise.race([timeout(100), changeFuture]);
// Delete file
changeFuture = awaitEvent(watcher, copiedFilepath, FileChangeType.DELETED);
@ -281,7 +278,7 @@ import { ltrim } from 'vs/base/common/strings';
// Delete + Recreate file
const newFilePath = join(testDir, 'deep', 'conway.js');
const changeFuture: Promise<unknown> = awaitEvent(watcher, newFilePath, FileChangeType.UPDATED);
const changeFuture = awaitEvent(watcher, newFilePath, FileChangeType.UPDATED);
await Promises.unlink(newFilePath);
Promises.writeFile(newFilePath, 'Hello Atomic World');
await changeFuture;
@ -296,7 +293,7 @@ import { ltrim } from 'vs/base/common/strings';
async function basicCrudTest(filePath: string): Promise<void> {
// New file
let changeFuture: Promise<unknown> = awaitEvent(watcher, filePath, FileChangeType.ADDED);
let changeFuture = awaitEvent(watcher, filePath, FileChangeType.ADDED);
await Promises.writeFile(filePath, 'Hello World');
await changeFuture;
@ -324,12 +321,12 @@ import { ltrim } from 'vs/base/common/strings';
const newFilePath5 = join(testDir, 'deep-multiple', 'newFile-2.txt');
const newFilePath6 = join(testDir, 'deep-multiple', 'newFile-3.txt');
const addedFuture1: Promise<unknown> = awaitEvent(watcher, newFilePath1, FileChangeType.ADDED);
const addedFuture2: Promise<unknown> = awaitEvent(watcher, newFilePath2, FileChangeType.ADDED);
const addedFuture3: Promise<unknown> = awaitEvent(watcher, newFilePath3, FileChangeType.ADDED);
const addedFuture4: Promise<unknown> = awaitEvent(watcher, newFilePath4, FileChangeType.ADDED);
const addedFuture5: Promise<unknown> = awaitEvent(watcher, newFilePath5, FileChangeType.ADDED);
const addedFuture6: Promise<unknown> = awaitEvent(watcher, newFilePath6, FileChangeType.ADDED);
const addedFuture1 = awaitEvent(watcher, newFilePath1, FileChangeType.ADDED);
const addedFuture2 = awaitEvent(watcher, newFilePath2, FileChangeType.ADDED);
const addedFuture3 = awaitEvent(watcher, newFilePath3, FileChangeType.ADDED);
const addedFuture4 = awaitEvent(watcher, newFilePath4, FileChangeType.ADDED);
const addedFuture5 = awaitEvent(watcher, newFilePath5, FileChangeType.ADDED);
const addedFuture6 = awaitEvent(watcher, newFilePath6, FileChangeType.ADDED);
await Promise.all([
await Promises.writeFile(newFilePath1, 'Hello World 1'),
@ -344,12 +341,12 @@ import { ltrim } from 'vs/base/common/strings';
// multiple change
const changeFuture1: Promise<unknown> = awaitEvent(watcher, newFilePath1, FileChangeType.UPDATED);
const changeFuture2: Promise<unknown> = awaitEvent(watcher, newFilePath2, FileChangeType.UPDATED);
const changeFuture3: Promise<unknown> = awaitEvent(watcher, newFilePath3, FileChangeType.UPDATED);
const changeFuture4: Promise<unknown> = awaitEvent(watcher, newFilePath4, FileChangeType.UPDATED);
const changeFuture5: Promise<unknown> = awaitEvent(watcher, newFilePath5, FileChangeType.UPDATED);
const changeFuture6: Promise<unknown> = awaitEvent(watcher, newFilePath6, FileChangeType.UPDATED);
const changeFuture1 = awaitEvent(watcher, newFilePath1, FileChangeType.UPDATED);
const changeFuture2 = awaitEvent(watcher, newFilePath2, FileChangeType.UPDATED);
const changeFuture3 = awaitEvent(watcher, newFilePath3, FileChangeType.UPDATED);
const changeFuture4 = awaitEvent(watcher, newFilePath4, FileChangeType.UPDATED);
const changeFuture5 = awaitEvent(watcher, newFilePath5, FileChangeType.UPDATED);
const changeFuture6 = awaitEvent(watcher, newFilePath6, FileChangeType.UPDATED);
await Promise.all([
await Promises.writeFile(newFilePath1, 'Hello Update 1'),
@ -364,10 +361,10 @@ import { ltrim } from 'vs/base/common/strings';
// copy with multiple files
const copyFuture1: Promise<unknown> = awaitEvent(watcher, join(testDir, 'deep-multiple-copy', 'newFile-1.txt'), FileChangeType.ADDED);
const copyFuture2: Promise<unknown> = awaitEvent(watcher, join(testDir, 'deep-multiple-copy', 'newFile-2.txt'), FileChangeType.ADDED);
const copyFuture3: Promise<unknown> = awaitEvent(watcher, join(testDir, 'deep-multiple-copy', 'newFile-3.txt'), FileChangeType.ADDED);
const copyFuture4: Promise<unknown> = awaitEvent(watcher, join(testDir, 'deep-multiple-copy'), FileChangeType.ADDED);
const copyFuture1 = awaitEvent(watcher, join(testDir, 'deep-multiple-copy', 'newFile-1.txt'), FileChangeType.ADDED);
const copyFuture2 = awaitEvent(watcher, join(testDir, 'deep-multiple-copy', 'newFile-2.txt'), FileChangeType.ADDED);
const copyFuture3 = awaitEvent(watcher, join(testDir, 'deep-multiple-copy', 'newFile-3.txt'), FileChangeType.ADDED);
const copyFuture4 = awaitEvent(watcher, join(testDir, 'deep-multiple-copy'), FileChangeType.ADDED);
await Promises.copy(join(testDir, 'deep-multiple'), join(testDir, 'deep-multiple-copy'), { preserveSymlinks: false });
@ -375,12 +372,12 @@ import { ltrim } from 'vs/base/common/strings';
// multiple delete (single files)
const deleteFuture1: Promise<unknown> = awaitEvent(watcher, newFilePath1, FileChangeType.DELETED);
const deleteFuture2: Promise<unknown> = awaitEvent(watcher, newFilePath2, FileChangeType.DELETED);
const deleteFuture3: Promise<unknown> = awaitEvent(watcher, newFilePath3, FileChangeType.DELETED);
const deleteFuture4: Promise<unknown> = awaitEvent(watcher, newFilePath4, FileChangeType.DELETED);
const deleteFuture5: Promise<unknown> = awaitEvent(watcher, newFilePath5, FileChangeType.DELETED);
const deleteFuture6: Promise<unknown> = awaitEvent(watcher, newFilePath6, FileChangeType.DELETED);
const deleteFuture1 = awaitEvent(watcher, newFilePath1, FileChangeType.DELETED);
const deleteFuture2 = awaitEvent(watcher, newFilePath2, FileChangeType.DELETED);
const deleteFuture3 = awaitEvent(watcher, newFilePath3, FileChangeType.DELETED);
const deleteFuture4 = awaitEvent(watcher, newFilePath4, FileChangeType.DELETED);
const deleteFuture5 = awaitEvent(watcher, newFilePath5, FileChangeType.DELETED);
const deleteFuture6 = awaitEvent(watcher, newFilePath6, FileChangeType.DELETED);
await Promise.all([
await Promises.unlink(newFilePath1),
@ -395,8 +392,8 @@ import { ltrim } from 'vs/base/common/strings';
// multiple delete (folder)
const deleteFolderFuture1: Promise<unknown> = awaitEvent(watcher, join(testDir, 'deep-multiple'), FileChangeType.DELETED);
const deleteFolderFuture2: Promise<unknown> = awaitEvent(watcher, join(testDir, 'deep-multiple-copy'), FileChangeType.DELETED);
const deleteFolderFuture1 = awaitEvent(watcher, join(testDir, 'deep-multiple'), FileChangeType.DELETED);
const deleteFolderFuture2 = awaitEvent(watcher, join(testDir, 'deep-multiple-copy'), FileChangeType.DELETED);
await Promise.all([Promises.rm(join(testDir, 'deep-multiple'), RimRafMode.UNLINK), Promises.rm(join(testDir, 'deep-multiple-copy'), RimRafMode.UNLINK)]);
@ -408,7 +405,7 @@ import { ltrim } from 'vs/base/common/strings';
// New file (*.txt)
let newTextFilePath = join(testDir, 'deep', 'newFile.txt');
let changeFuture: Promise<unknown> = awaitEvent(watcher, newTextFilePath, FileChangeType.ADDED);
let changeFuture = awaitEvent(watcher, newTextFilePath, FileChangeType.ADDED);
await Promises.writeFile(newTextFilePath, 'Hello World');
await changeFuture;

View file

@ -628,10 +628,10 @@
resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.0.3.tgz#13a12ae9e05c2a782f7b5e84c3cbfda4225eaf80"
integrity sha512-puWxACExDe9nxbBB3lOymQFrLYml2dVOrd7USiVRnSbgXE+KwBu+HxFvxrzfqsiSda9IWsXJG1ef7C1O2/GmKQ==
"@parcel/watcher@2.0.5":
version "2.0.5"
resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.0.5.tgz#f913a54e1601b0aac972803829b0eece48de215b"
integrity sha512-x0hUbjv891omnkcHD7ZOhiyyUqUUR6MNjq89JhEI3BxppeKWAm6NPQsqqRrAkCJBogdT/o/My21sXtTI9rJIsw==
"@parcel/watcher@2.0.7":
version "2.0.7"
resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.0.7.tgz#c95fe1370e8c6237cb9729c9c075264acc7e21a5"
integrity sha512-gc3hoS6e+2XdIQ4HHljDB1l0Yx2EWh/sBBtCEFNKGSMlwASWeAQsOY/fPbxOBcZ/pg0jBh4Ga+4xHlZc4faAEQ==
dependencies:
node-addon-api "^3.2.1"
node-gyp-build "^4.3.0"