vscode-fs 0.0.3 → 0.0.5

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/dist/index.cjs CHANGED
@@ -46,6 +46,54 @@ let FileSystemProviderErrorCode = /* @__PURE__ */ function(FileSystemProviderErr
46
46
  FileSystemProviderErrorCode["Unknown"] = "Unknown";
47
47
  return FileSystemProviderErrorCode;
48
48
  }({});
49
+ /**
50
+ * A relative pattern is a helper to construct glob patterns that are matched
51
+ * relatively to a base file path. The base path can either be an absolute file
52
+ * path as string or uri or a {@link WorkspaceFolder workspace folder}, which is the
53
+ * preferred way of creating the relative pattern.
54
+ */
55
+ var RelativePattern = class {
56
+ /**
57
+ * A base file path to which this pattern will be matched against relatively. The
58
+ * file path must be absolute, should not have any trailing path separators and
59
+ * not include any relative segments (`.` or `..`).
60
+ */
61
+ baseUri;
62
+ /**
63
+ * A file glob pattern like `*.{ts,js}` that will be matched on file paths
64
+ * relative to the base path.
65
+ *
66
+ * Example: Given a base of `/home/work/folder` and a file path of `/home/work/folder/index.js`,
67
+ * the file glob pattern will match on `index.js`.
68
+ */
69
+ pattern;
70
+ /**
71
+ * Creates a new relative pattern object with a base file path and pattern to match. This pattern
72
+ * will be matched on file paths relative to the base.
73
+ *
74
+ * Example:
75
+ * ```ts
76
+ * const folder = vscode.workspace.workspaceFolders?.[0];
77
+ * if (folder) {
78
+ *
79
+ * // Match any TypeScript file in the root of this workspace folder
80
+ * const pattern1 = new vscode.RelativePattern(folder, '*.ts');
81
+ *
82
+ * // Match any TypeScript file in `someFolder` inside this workspace folder
83
+ * const pattern2 = new vscode.RelativePattern(folder, 'someFolder/*.ts');
84
+ * }
85
+ * ```
86
+ *
87
+ * @param base A base to which this pattern will be matched against relatively. It is recommended
88
+ * to pass in a {@link WorkspaceFolder workspace folder} if the pattern should match inside the workspace.
89
+ * Otherwise, a uri or string should only be used if the pattern is for a file path outside the workspace.
90
+ * @param pattern A file glob pattern like `*.{ts,js}` that will be matched on paths relative to the base.
91
+ */
92
+ constructor(base, pattern) {
93
+ this.baseUri = base;
94
+ this.pattern = pattern;
95
+ }
96
+ };
49
97
 
50
98
  //#endregion
51
99
  //#region src/error.ts
@@ -119,7 +167,12 @@ function joinPath(basePath, ...segments) {
119
167
  return vscode_uri.Utils.joinPath(vscode_uri.URI.file(basePath), ...segments).fsPath;
120
168
  }
121
169
  async function createNodeFileSystem() {
122
- const [fs, trash] = await Promise.all([import("node:fs"), import("trash").then((m) => m.default)]);
170
+ const [fs, trash, glob, watch] = await Promise.all([
171
+ import("node:fs"),
172
+ import("trash").then((m) => m.default),
173
+ import("tinyglobby").then((m) => m.glob),
174
+ import("chokidar").then((m) => m.watch)
175
+ ]);
123
176
  async function resolveFileType(path) {
124
177
  const lstats = await fs.promises.lstat(path);
125
178
  if (!lstats.isSymbolicLink()) return {
@@ -169,6 +222,9 @@ async function createNodeFileSystem() {
169
222
  }
170
223
  throw createFileSystemError(`Unsupported file type: ${sourcePath}`, FileSystemProviderErrorCode.Unknown);
171
224
  }
225
+ function pathToUris(pathToUris) {
226
+ return pathToUris.map((path) => vscode_uri.URI.file(path));
227
+ }
172
228
  return {
173
229
  stat: (uri) => wrap(async () => {
174
230
  const { type, stats } = await resolveFileType(uri.fsPath);
@@ -254,6 +310,52 @@ async function createNodeFileSystem() {
254
310
  } catch {
255
311
  return false;
256
312
  }
313
+ },
314
+ glob: async (pattern, options) => {
315
+ return pathToUris(await glob(pattern.pattern, {
316
+ absolute: true,
317
+ cwd: pattern.baseUri.fsPath,
318
+ onlyFiles: options?.onlyFiles,
319
+ onlyDirectories: options?.onlyDirectories,
320
+ followSymbolicLinks: options?.followSymbolicLinks,
321
+ ignore: options?.ignore,
322
+ dot: options?.dot,
323
+ expandDirectories: options?.expandDirectories,
324
+ extglob: options?.extglob,
325
+ deep: options?.deep,
326
+ fs
327
+ }));
328
+ },
329
+ createWatcher: async (pattern, options) => {
330
+ const watcher = watch(pattern.pattern, { cwd: pattern.baseUri.fsPath });
331
+ return new Promise((resolve) => {
332
+ watcher.on("ready", () => {
333
+ const onDidCreateListeners = /* @__PURE__ */ new Set();
334
+ const onDidChangeListeners = /* @__PURE__ */ new Set();
335
+ const onDidDeleteListeners = /* @__PURE__ */ new Set();
336
+ if (options?.ignoreChangeEvents !== true) watcher.on("add", (path) => onDidCreateListeners.forEach((listener) => listener(vscode_uri.URI.file(path))));
337
+ if (options?.ignoreChangeEvents !== true) watcher.on("change", (path) => onDidChangeListeners.forEach((listener) => listener(vscode_uri.URI.file(path))));
338
+ if (options?.ignoreDeleteEvents !== true) watcher.on("unlink", (path) => onDidDeleteListeners.forEach((listener) => listener(vscode_uri.URI.file(path))));
339
+ resolve({
340
+ ignoreChangeEvents: options?.ignoreChangeEvents ?? false,
341
+ ignoreCreateEvents: options?.ignoreCreateEvents ?? false,
342
+ ignoreDeleteEvents: options?.ignoreDeleteEvents ?? false,
343
+ onDidCreate: (listener) => {
344
+ onDidCreateListeners.add(listener);
345
+ return { dispose: () => onDidCreateListeners.delete(listener) };
346
+ },
347
+ onDidChange: (listener) => {
348
+ onDidChangeListeners.add(listener);
349
+ return { dispose: () => onDidChangeListeners.delete(listener) };
350
+ },
351
+ onDidDelete: (listener) => {
352
+ onDidDeleteListeners.add(listener);
353
+ return { dispose: () => onDidDeleteListeners.delete(listener) };
354
+ },
355
+ dispose: () => watcher.close()
356
+ });
357
+ });
358
+ });
257
359
  }
258
360
  };
259
361
  }
@@ -267,6 +369,7 @@ Object.defineProperty(exports, 'FileSystemError', {
267
369
  });
268
370
  exports.FileSystemProviderErrorCode = FileSystemProviderErrorCode;
269
371
  exports.FileType = FileType;
372
+ exports.RelativePattern = RelativePattern;
270
373
  exports.createFileSystemError = createFileSystemError;
271
374
  exports.createNodeFileSystem = createNodeFileSystem;
272
375
  exports.toFileSystemError = toFileSystemError;
package/dist/index.d.cts CHANGED
@@ -146,6 +146,132 @@ interface FileSystem {
146
146
  * @throws It will not throw any errors if the file, directory, or symbolic link does not exist.
147
147
  */
148
148
  exists(uri: URI): Promise<FileStat | false>;
149
+ /**
150
+ * Glob files by pattern.
151
+ *
152
+ * @param globPattern The glob pattern.
153
+ * @param options The options for the glob.
154
+ * @param options.onlyFiles Only include files in the results. Default is `true`.
155
+ * @param options.onlyDirectories Only include directories in the results. Default is `false`.
156
+ * @param options.followSymbolicLinks Follow symbolic links in the results. Default is `true`.
157
+ * @param options.ignore Ignore files in the results. Default is `[]`.
158
+ * @param options.dot Include files and directories that start with a dot like `.gitignore`. Default is `true`.
159
+ * @param options.expandDirectories Whether to automatically expand directory patterns. Default is `true`. Important to disable if migrating from [`fast-glob`](https://github.com/mrmlnc/fast-glob).
160
+ * @param options.extglob Enables support for extglobs, like `+(pattern)`. Default is `true`.
161
+ * @param options.deep Maximum directory depth to crawl. Default is `Infinity`.
162
+ * @returns An array of file uris.
163
+ */
164
+ glob(globPattern: RelativePattern, options?: {
165
+ /**
166
+ * Only include files in the results.
167
+ *
168
+ * @default true
169
+ */
170
+ onlyFiles?: boolean;
171
+ /**
172
+ * Only include directories in the results.
173
+ *
174
+ * @default false
175
+ */
176
+ onlyDirectories?: boolean;
177
+ /**
178
+ * Follow symbolic links in the results.
179
+ *
180
+ * @default true
181
+ */
182
+ followSymbolicLinks?: boolean;
183
+ /**
184
+ * Ignore files in the results.
185
+ *
186
+ * @default []
187
+ */
188
+ ignore?: string[];
189
+ /**
190
+ * Include files and directories that start with a dot like `.gitignore`.
191
+ *
192
+ * @default true
193
+ */
194
+ dot?: boolean;
195
+ /**
196
+ * Whether to automatically expand directory patterns.
197
+ *
198
+ * Important to disable if migrating from [`fast-glob`](https://github.com/mrmlnc/fast-glob).
199
+ *
200
+ * @default true
201
+ */
202
+ expandDirectories?: boolean;
203
+ /**
204
+ * Enables support for extglobs, like `+(pattern)`.
205
+ *
206
+ * @default true
207
+ */
208
+ extglob?: boolean;
209
+ /**
210
+ * Maximum directory depth to crawl.
211
+ * @default Infinity
212
+ */
213
+ deep?: number;
214
+ }): Promise<URI[]>;
215
+ createWatcher(pattern: RelativePattern, options?: {
216
+ /**
217
+ * Ignore create events.
218
+ *
219
+ * @default false
220
+ */
221
+ ignoreCreateEvents?: boolean;
222
+ /**
223
+ * Ignore change events.
224
+ *
225
+ * @default false
226
+ */
227
+ ignoreChangeEvents?: boolean;
228
+ /**
229
+ * Ignore delete events.
230
+ *
231
+ * @default false
232
+ */
233
+ ignoreDeleteEvents?: boolean;
234
+ }): Promise<FileSystemWatcher>;
235
+ }
236
+ interface Disposable {
237
+ /** Dispose resources. */
238
+ dispose(): unknown;
239
+ }
240
+ /**
241
+ * A file system watcher notifies about changes to files and folders
242
+ * on disk or from other {@link FileSystemProvider FileSystemProviders}.
243
+ *
244
+ * To get an instance of a `FileSystemWatcher` use
245
+ * {@link workspace.createFileSystemWatcher createFileSystemWatcher}.
246
+ */
247
+ interface FileSystemWatcher extends Disposable {
248
+ /**
249
+ * true if this file system watcher has been created such that
250
+ * it ignores creation file system events.
251
+ */
252
+ readonly ignoreCreateEvents: boolean;
253
+ /**
254
+ * true if this file system watcher has been created such that
255
+ * it ignores change file system events.
256
+ */
257
+ readonly ignoreChangeEvents: boolean;
258
+ /**
259
+ * true if this file system watcher has been created such that
260
+ * it ignores delete file system events.
261
+ */
262
+ readonly ignoreDeleteEvents: boolean;
263
+ /**
264
+ * An event which fires on file/folder creation.
265
+ */
266
+ onDidCreate(listener: (e: URI) => unknown): Disposable;
267
+ /**
268
+ * An event which fires on file/folder change.
269
+ */
270
+ onDidChange(listener: (e: URI) => unknown): Disposable;
271
+ /**
272
+ * An event which fires on file/folder deletion.
273
+ */
274
+ onDidDelete(listener: (e: URI) => unknown): Disposable;
149
275
  }
150
276
  /**
151
277
  * The `FileStat`-type represents metadata about a file
@@ -218,6 +344,51 @@ declare enum FileSystemProviderErrorCode {
218
344
  Unavailable = "Unavailable",
219
345
  Unknown = "Unknown"
220
346
  }
347
+ /**
348
+ * A relative pattern is a helper to construct glob patterns that are matched
349
+ * relatively to a base file path. The base path can either be an absolute file
350
+ * path as string or uri or a {@link WorkspaceFolder workspace folder}, which is the
351
+ * preferred way of creating the relative pattern.
352
+ */
353
+ declare class RelativePattern {
354
+ /**
355
+ * A base file path to which this pattern will be matched against relatively. The
356
+ * file path must be absolute, should not have any trailing path separators and
357
+ * not include any relative segments (`.` or `..`).
358
+ */
359
+ baseUri: URI;
360
+ /**
361
+ * A file glob pattern like `*.{ts,js}` that will be matched on file paths
362
+ * relative to the base path.
363
+ *
364
+ * Example: Given a base of `/home/work/folder` and a file path of `/home/work/folder/index.js`,
365
+ * the file glob pattern will match on `index.js`.
366
+ */
367
+ pattern: string;
368
+ /**
369
+ * Creates a new relative pattern object with a base file path and pattern to match. This pattern
370
+ * will be matched on file paths relative to the base.
371
+ *
372
+ * Example:
373
+ * ```ts
374
+ * const folder = vscode.workspace.workspaceFolders?.[0];
375
+ * if (folder) {
376
+ *
377
+ * // Match any TypeScript file in the root of this workspace folder
378
+ * const pattern1 = new vscode.RelativePattern(folder, '*.ts');
379
+ *
380
+ * // Match any TypeScript file in `someFolder` inside this workspace folder
381
+ * const pattern2 = new vscode.RelativePattern(folder, 'someFolder/*.ts');
382
+ * }
383
+ * ```
384
+ *
385
+ * @param base A base to which this pattern will be matched against relatively. It is recommended
386
+ * to pass in a {@link WorkspaceFolder workspace folder} if the pattern should match inside the workspace.
387
+ * Otherwise, a uri or string should only be used if the pattern is for a file path outside the workspace.
388
+ * @param pattern A file glob pattern like `*.{ts,js}` that will be matched on paths relative to the base.
389
+ */
390
+ constructor(base: URI, pattern: string);
391
+ }
221
392
  //#endregion
222
393
  //#region src/error.d.ts
223
394
  declare function createFileSystemError(error: Error | string, code: FileSystemProviderErrorCode): FileSystemError;
@@ -226,4 +397,4 @@ declare function toFileSystemError(error: NodeJS.ErrnoException): FileSystemErro
226
397
  //#region src/node.d.ts
227
398
  declare function createNodeFileSystem(): Promise<FileSystem>;
228
399
  //#endregion
229
- export { FileStat, FileSystem, FileSystemError, FileSystemProviderErrorCode, FileType, IsDirectory, IsFile, IsSymbolicLink, createFileSystemError, createNodeFileSystem, toFileSystemError };
400
+ export { Disposable, FileStat, FileSystem, FileSystemError, FileSystemProviderErrorCode, FileSystemWatcher, FileType, IsDirectory, IsFile, IsSymbolicLink, RelativePattern, createFileSystemError, createNodeFileSystem, toFileSystemError };
package/dist/index.d.mts CHANGED
@@ -146,6 +146,132 @@ interface FileSystem {
146
146
  * @throws It will not throw any errors if the file, directory, or symbolic link does not exist.
147
147
  */
148
148
  exists(uri: URI): Promise<FileStat | false>;
149
+ /**
150
+ * Glob files by pattern.
151
+ *
152
+ * @param globPattern The glob pattern.
153
+ * @param options The options for the glob.
154
+ * @param options.onlyFiles Only include files in the results. Default is `true`.
155
+ * @param options.onlyDirectories Only include directories in the results. Default is `false`.
156
+ * @param options.followSymbolicLinks Follow symbolic links in the results. Default is `true`.
157
+ * @param options.ignore Ignore files in the results. Default is `[]`.
158
+ * @param options.dot Include files and directories that start with a dot like `.gitignore`. Default is `true`.
159
+ * @param options.expandDirectories Whether to automatically expand directory patterns. Default is `true`. Important to disable if migrating from [`fast-glob`](https://github.com/mrmlnc/fast-glob).
160
+ * @param options.extglob Enables support for extglobs, like `+(pattern)`. Default is `true`.
161
+ * @param options.deep Maximum directory depth to crawl. Default is `Infinity`.
162
+ * @returns An array of file uris.
163
+ */
164
+ glob(globPattern: RelativePattern, options?: {
165
+ /**
166
+ * Only include files in the results.
167
+ *
168
+ * @default true
169
+ */
170
+ onlyFiles?: boolean;
171
+ /**
172
+ * Only include directories in the results.
173
+ *
174
+ * @default false
175
+ */
176
+ onlyDirectories?: boolean;
177
+ /**
178
+ * Follow symbolic links in the results.
179
+ *
180
+ * @default true
181
+ */
182
+ followSymbolicLinks?: boolean;
183
+ /**
184
+ * Ignore files in the results.
185
+ *
186
+ * @default []
187
+ */
188
+ ignore?: string[];
189
+ /**
190
+ * Include files and directories that start with a dot like `.gitignore`.
191
+ *
192
+ * @default true
193
+ */
194
+ dot?: boolean;
195
+ /**
196
+ * Whether to automatically expand directory patterns.
197
+ *
198
+ * Important to disable if migrating from [`fast-glob`](https://github.com/mrmlnc/fast-glob).
199
+ *
200
+ * @default true
201
+ */
202
+ expandDirectories?: boolean;
203
+ /**
204
+ * Enables support for extglobs, like `+(pattern)`.
205
+ *
206
+ * @default true
207
+ */
208
+ extglob?: boolean;
209
+ /**
210
+ * Maximum directory depth to crawl.
211
+ * @default Infinity
212
+ */
213
+ deep?: number;
214
+ }): Promise<URI[]>;
215
+ createWatcher(pattern: RelativePattern, options?: {
216
+ /**
217
+ * Ignore create events.
218
+ *
219
+ * @default false
220
+ */
221
+ ignoreCreateEvents?: boolean;
222
+ /**
223
+ * Ignore change events.
224
+ *
225
+ * @default false
226
+ */
227
+ ignoreChangeEvents?: boolean;
228
+ /**
229
+ * Ignore delete events.
230
+ *
231
+ * @default false
232
+ */
233
+ ignoreDeleteEvents?: boolean;
234
+ }): Promise<FileSystemWatcher>;
235
+ }
236
+ interface Disposable {
237
+ /** Dispose resources. */
238
+ dispose(): unknown;
239
+ }
240
+ /**
241
+ * A file system watcher notifies about changes to files and folders
242
+ * on disk or from other {@link FileSystemProvider FileSystemProviders}.
243
+ *
244
+ * To get an instance of a `FileSystemWatcher` use
245
+ * {@link workspace.createFileSystemWatcher createFileSystemWatcher}.
246
+ */
247
+ interface FileSystemWatcher extends Disposable {
248
+ /**
249
+ * true if this file system watcher has been created such that
250
+ * it ignores creation file system events.
251
+ */
252
+ readonly ignoreCreateEvents: boolean;
253
+ /**
254
+ * true if this file system watcher has been created such that
255
+ * it ignores change file system events.
256
+ */
257
+ readonly ignoreChangeEvents: boolean;
258
+ /**
259
+ * true if this file system watcher has been created such that
260
+ * it ignores delete file system events.
261
+ */
262
+ readonly ignoreDeleteEvents: boolean;
263
+ /**
264
+ * An event which fires on file/folder creation.
265
+ */
266
+ onDidCreate(listener: (e: URI) => unknown): Disposable;
267
+ /**
268
+ * An event which fires on file/folder change.
269
+ */
270
+ onDidChange(listener: (e: URI) => unknown): Disposable;
271
+ /**
272
+ * An event which fires on file/folder deletion.
273
+ */
274
+ onDidDelete(listener: (e: URI) => unknown): Disposable;
149
275
  }
150
276
  /**
151
277
  * The `FileStat`-type represents metadata about a file
@@ -218,6 +344,51 @@ declare enum FileSystemProviderErrorCode {
218
344
  Unavailable = "Unavailable",
219
345
  Unknown = "Unknown"
220
346
  }
347
+ /**
348
+ * A relative pattern is a helper to construct glob patterns that are matched
349
+ * relatively to a base file path. The base path can either be an absolute file
350
+ * path as string or uri or a {@link WorkspaceFolder workspace folder}, which is the
351
+ * preferred way of creating the relative pattern.
352
+ */
353
+ declare class RelativePattern {
354
+ /**
355
+ * A base file path to which this pattern will be matched against relatively. The
356
+ * file path must be absolute, should not have any trailing path separators and
357
+ * not include any relative segments (`.` or `..`).
358
+ */
359
+ baseUri: URI;
360
+ /**
361
+ * A file glob pattern like `*.{ts,js}` that will be matched on file paths
362
+ * relative to the base path.
363
+ *
364
+ * Example: Given a base of `/home/work/folder` and a file path of `/home/work/folder/index.js`,
365
+ * the file glob pattern will match on `index.js`.
366
+ */
367
+ pattern: string;
368
+ /**
369
+ * Creates a new relative pattern object with a base file path and pattern to match. This pattern
370
+ * will be matched on file paths relative to the base.
371
+ *
372
+ * Example:
373
+ * ```ts
374
+ * const folder = vscode.workspace.workspaceFolders?.[0];
375
+ * if (folder) {
376
+ *
377
+ * // Match any TypeScript file in the root of this workspace folder
378
+ * const pattern1 = new vscode.RelativePattern(folder, '*.ts');
379
+ *
380
+ * // Match any TypeScript file in `someFolder` inside this workspace folder
381
+ * const pattern2 = new vscode.RelativePattern(folder, 'someFolder/*.ts');
382
+ * }
383
+ * ```
384
+ *
385
+ * @param base A base to which this pattern will be matched against relatively. It is recommended
386
+ * to pass in a {@link WorkspaceFolder workspace folder} if the pattern should match inside the workspace.
387
+ * Otherwise, a uri or string should only be used if the pattern is for a file path outside the workspace.
388
+ * @param pattern A file glob pattern like `*.{ts,js}` that will be matched on paths relative to the base.
389
+ */
390
+ constructor(base: URI, pattern: string);
391
+ }
221
392
  //#endregion
222
393
  //#region src/error.d.ts
223
394
  declare function createFileSystemError(error: Error | string, code: FileSystemProviderErrorCode): FileSystemError;
@@ -226,4 +397,4 @@ declare function toFileSystemError(error: NodeJS.ErrnoException): FileSystemErro
226
397
  //#region src/node.d.ts
227
398
  declare function createNodeFileSystem(): Promise<FileSystem>;
228
399
  //#endregion
229
- export { FileStat, FileSystem, FileSystemError, FileSystemProviderErrorCode, FileType, IsDirectory, IsFile, IsSymbolicLink, createFileSystemError, createNodeFileSystem, toFileSystemError };
400
+ export { Disposable, FileStat, FileSystem, FileSystemError, FileSystemProviderErrorCode, FileSystemWatcher, FileType, IsDirectory, IsFile, IsSymbolicLink, RelativePattern, createFileSystemError, createNodeFileSystem, toFileSystemError };
package/dist/index.mjs CHANGED
@@ -45,6 +45,54 @@ let FileSystemProviderErrorCode = /* @__PURE__ */ function(FileSystemProviderErr
45
45
  FileSystemProviderErrorCode["Unknown"] = "Unknown";
46
46
  return FileSystemProviderErrorCode;
47
47
  }({});
48
+ /**
49
+ * A relative pattern is a helper to construct glob patterns that are matched
50
+ * relatively to a base file path. The base path can either be an absolute file
51
+ * path as string or uri or a {@link WorkspaceFolder workspace folder}, which is the
52
+ * preferred way of creating the relative pattern.
53
+ */
54
+ var RelativePattern = class {
55
+ /**
56
+ * A base file path to which this pattern will be matched against relatively. The
57
+ * file path must be absolute, should not have any trailing path separators and
58
+ * not include any relative segments (`.` or `..`).
59
+ */
60
+ baseUri;
61
+ /**
62
+ * A file glob pattern like `*.{ts,js}` that will be matched on file paths
63
+ * relative to the base path.
64
+ *
65
+ * Example: Given a base of `/home/work/folder` and a file path of `/home/work/folder/index.js`,
66
+ * the file glob pattern will match on `index.js`.
67
+ */
68
+ pattern;
69
+ /**
70
+ * Creates a new relative pattern object with a base file path and pattern to match. This pattern
71
+ * will be matched on file paths relative to the base.
72
+ *
73
+ * Example:
74
+ * ```ts
75
+ * const folder = vscode.workspace.workspaceFolders?.[0];
76
+ * if (folder) {
77
+ *
78
+ * // Match any TypeScript file in the root of this workspace folder
79
+ * const pattern1 = new vscode.RelativePattern(folder, '*.ts');
80
+ *
81
+ * // Match any TypeScript file in `someFolder` inside this workspace folder
82
+ * const pattern2 = new vscode.RelativePattern(folder, 'someFolder/*.ts');
83
+ * }
84
+ * ```
85
+ *
86
+ * @param base A base to which this pattern will be matched against relatively. It is recommended
87
+ * to pass in a {@link WorkspaceFolder workspace folder} if the pattern should match inside the workspace.
88
+ * Otherwise, a uri or string should only be used if the pattern is for a file path outside the workspace.
89
+ * @param pattern A file glob pattern like `*.{ts,js}` that will be matched on paths relative to the base.
90
+ */
91
+ constructor(base, pattern) {
92
+ this.baseUri = base;
93
+ this.pattern = pattern;
94
+ }
95
+ };
48
96
 
49
97
  //#endregion
50
98
  //#region src/error.ts
@@ -118,7 +166,12 @@ function joinPath(basePath, ...segments) {
118
166
  return Utils.joinPath(URI.file(basePath), ...segments).fsPath;
119
167
  }
120
168
  async function createNodeFileSystem() {
121
- const [fs, trash] = await Promise.all([import("node:fs"), import("trash").then((m) => m.default)]);
169
+ const [fs, trash, glob, watch] = await Promise.all([
170
+ import("node:fs"),
171
+ import("trash").then((m) => m.default),
172
+ import("tinyglobby").then((m) => m.glob),
173
+ import("chokidar").then((m) => m.watch)
174
+ ]);
122
175
  async function resolveFileType(path) {
123
176
  const lstats = await fs.promises.lstat(path);
124
177
  if (!lstats.isSymbolicLink()) return {
@@ -168,6 +221,9 @@ async function createNodeFileSystem() {
168
221
  }
169
222
  throw createFileSystemError(`Unsupported file type: ${sourcePath}`, FileSystemProviderErrorCode.Unknown);
170
223
  }
224
+ function pathToUris(pathToUris) {
225
+ return pathToUris.map((path) => URI.file(path));
226
+ }
171
227
  return {
172
228
  stat: (uri) => wrap(async () => {
173
229
  const { type, stats } = await resolveFileType(uri.fsPath);
@@ -253,9 +309,55 @@ async function createNodeFileSystem() {
253
309
  } catch {
254
310
  return false;
255
311
  }
312
+ },
313
+ glob: async (pattern, options) => {
314
+ return pathToUris(await glob(pattern.pattern, {
315
+ absolute: true,
316
+ cwd: pattern.baseUri.fsPath,
317
+ onlyFiles: options?.onlyFiles,
318
+ onlyDirectories: options?.onlyDirectories,
319
+ followSymbolicLinks: options?.followSymbolicLinks,
320
+ ignore: options?.ignore,
321
+ dot: options?.dot,
322
+ expandDirectories: options?.expandDirectories,
323
+ extglob: options?.extglob,
324
+ deep: options?.deep,
325
+ fs
326
+ }));
327
+ },
328
+ createWatcher: async (pattern, options) => {
329
+ const watcher = watch(pattern.pattern, { cwd: pattern.baseUri.fsPath });
330
+ return new Promise((resolve) => {
331
+ watcher.on("ready", () => {
332
+ const onDidCreateListeners = /* @__PURE__ */ new Set();
333
+ const onDidChangeListeners = /* @__PURE__ */ new Set();
334
+ const onDidDeleteListeners = /* @__PURE__ */ new Set();
335
+ if (options?.ignoreChangeEvents !== true) watcher.on("add", (path) => onDidCreateListeners.forEach((listener) => listener(URI.file(path))));
336
+ if (options?.ignoreChangeEvents !== true) watcher.on("change", (path) => onDidChangeListeners.forEach((listener) => listener(URI.file(path))));
337
+ if (options?.ignoreDeleteEvents !== true) watcher.on("unlink", (path) => onDidDeleteListeners.forEach((listener) => listener(URI.file(path))));
338
+ resolve({
339
+ ignoreChangeEvents: options?.ignoreChangeEvents ?? false,
340
+ ignoreCreateEvents: options?.ignoreCreateEvents ?? false,
341
+ ignoreDeleteEvents: options?.ignoreDeleteEvents ?? false,
342
+ onDidCreate: (listener) => {
343
+ onDidCreateListeners.add(listener);
344
+ return { dispose: () => onDidCreateListeners.delete(listener) };
345
+ },
346
+ onDidChange: (listener) => {
347
+ onDidChangeListeners.add(listener);
348
+ return { dispose: () => onDidChangeListeners.delete(listener) };
349
+ },
350
+ onDidDelete: (listener) => {
351
+ onDidDeleteListeners.add(listener);
352
+ return { dispose: () => onDidDeleteListeners.delete(listener) };
353
+ },
354
+ dispose: () => watcher.close()
355
+ });
356
+ });
357
+ });
256
358
  }
257
359
  };
258
360
  }
259
361
 
260
362
  //#endregion
261
- export { FileSystemError, FileSystemProviderErrorCode, FileType, createFileSystemError, createNodeFileSystem, toFileSystemError };
363
+ export { FileSystemError, FileSystemProviderErrorCode, FileType, RelativePattern, createFileSystemError, createNodeFileSystem, toFileSystemError };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vscode-fs",
3
3
  "type": "module",
4
- "version": "0.0.3",
4
+ "version": "0.0.5",
5
5
  "description": "VSCode like simple、serializable and cross-platform file system utilities.",
6
6
  "author": "Naily Zero <zero@naily.cc> (https://naily.cc)",
7
7
  "license": "MIT",
@@ -45,6 +45,8 @@
45
45
  "vscode-uri": "^3.1.0"
46
46
  },
47
47
  "dependencies": {
48
+ "chokidar": "^5.0.0",
49
+ "tinyglobby": "^0.2.15",
48
50
  "trash": "^10.1.1"
49
51
  },
50
52
  "devDependencies": {