@jsenv/filesystem 4.2.6 → 4.3.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/filesystem",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.3.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -16,6 +16,9 @@
|
|
|
16
16
|
"url": "https://twitter.com/damienmaillard"
|
|
17
17
|
},
|
|
18
18
|
"type": "module",
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=19.1.0"
|
|
21
|
+
},
|
|
19
22
|
"exports": {
|
|
20
23
|
".": {
|
|
21
24
|
"import": "./src/main.js"
|
|
@@ -16,7 +16,9 @@ export const createWatcher = (sourcePath, options) => {
|
|
|
16
16
|
if (e.code === "ENOENT") {
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
|
-
console.error(
|
|
19
|
+
console.error(
|
|
20
|
+
`error while trying to get rid of windows EPERM: ${e.stack}`,
|
|
21
|
+
);
|
|
20
22
|
throw error;
|
|
21
23
|
}
|
|
22
24
|
} else {
|
|
@@ -8,9 +8,7 @@ import { guardTooFastSecondCallPerFile } from "./internal/guard_second_call.js";
|
|
|
8
8
|
import { createWatcher } from "./internal/createWatcher.js";
|
|
9
9
|
import { trackResources } from "./internal/track_resources.js";
|
|
10
10
|
|
|
11
|
-
const
|
|
12
|
-
// linux does not support recursive option
|
|
13
|
-
const fsWatchSupportsRecursive = !isLinux;
|
|
11
|
+
const fsWatchSupportsRecursive = process.platform !== "linux";
|
|
14
12
|
|
|
15
13
|
export const registerDirectoryLifecycle = (
|
|
16
14
|
source,
|
|
@@ -93,8 +91,8 @@ export const registerDirectoryLifecycle = (
|
|
|
93
91
|
try {
|
|
94
92
|
const relativeUrl = urlToRelativeUrl(url, source);
|
|
95
93
|
const previousInfo = infoMap.get(relativeUrl);
|
|
96
|
-
const
|
|
97
|
-
const type = statsToType(
|
|
94
|
+
const stat = statSync(new URL(url));
|
|
95
|
+
const type = statsToType(stat);
|
|
98
96
|
const patternValue = previousInfo
|
|
99
97
|
? previousInfo.patternValue
|
|
100
98
|
: getWatchPatternValue({ url, type });
|
|
@@ -103,13 +101,15 @@ export const registerDirectoryLifecycle = (
|
|
|
103
101
|
url,
|
|
104
102
|
relativeUrl,
|
|
105
103
|
type,
|
|
106
|
-
|
|
107
|
-
mtimeMs: stats.mtimeMs,
|
|
104
|
+
stat,
|
|
108
105
|
patternValue,
|
|
109
106
|
};
|
|
110
107
|
} catch (e) {
|
|
111
108
|
if (e.code === "ENOENT") {
|
|
112
|
-
return
|
|
109
|
+
return {
|
|
110
|
+
type: null,
|
|
111
|
+
stat: null,
|
|
112
|
+
};
|
|
113
113
|
}
|
|
114
114
|
throw e;
|
|
115
115
|
}
|
|
@@ -182,7 +182,7 @@ export const registerDirectoryLifecycle = (
|
|
|
182
182
|
const handleChange = (relativeUrl) => {
|
|
183
183
|
const entryUrl = new URL(relativeUrl, sourceUrl).href;
|
|
184
184
|
const entryInfo = readEntryInfo(entryUrl);
|
|
185
|
-
if (
|
|
185
|
+
if (entryInfo.type === null) {
|
|
186
186
|
const previousEntryInfo = infoMap.get(relativeUrl);
|
|
187
187
|
if (!previousEntryInfo) {
|
|
188
188
|
// on MacOS it's possible to receive a "rename" event for
|
|
@@ -242,7 +242,7 @@ export const registerDirectoryLifecycle = (
|
|
|
242
242
|
readdirSync(new URL(directoryUrl)).forEach((entryName) => {
|
|
243
243
|
const childEntryUrl = new URL(entryName, directoryUrl).href;
|
|
244
244
|
const childEntryInfo = readEntryInfo(childEntryUrl);
|
|
245
|
-
if (childEntryInfo && childEntryInfo.patternValue) {
|
|
245
|
+
if (childEntryInfo.type !== null && childEntryInfo.patternValue) {
|
|
246
246
|
handleEntryFound(childEntryInfo, { notify });
|
|
247
247
|
}
|
|
248
248
|
});
|
|
@@ -271,7 +271,7 @@ export const registerDirectoryLifecycle = (
|
|
|
271
271
|
relativeUrl: entryInfo.relativeUrl,
|
|
272
272
|
type: entryInfo.type,
|
|
273
273
|
patternValue: entryInfo.patternValue,
|
|
274
|
-
mtime: entryInfo.mtimeMs,
|
|
274
|
+
mtime: entryInfo.stat.mtimeMs,
|
|
275
275
|
});
|
|
276
276
|
}
|
|
277
277
|
};
|
|
@@ -282,19 +282,19 @@ export const registerDirectoryLifecycle = (
|
|
|
282
282
|
relativeUrl: entryInfo.relativeUrl,
|
|
283
283
|
type: entryInfo.type,
|
|
284
284
|
patternValue: entryInfo.patternValue,
|
|
285
|
-
mtime: entryInfo.mtimeMs,
|
|
285
|
+
mtime: entryInfo.stat.mtimeMs,
|
|
286
286
|
});
|
|
287
287
|
}
|
|
288
288
|
};
|
|
289
289
|
const handleEntryUpdated = (entryInfo) => {
|
|
290
290
|
infoMap.set(entryInfo.relativeUrl, entryInfo);
|
|
291
|
-
if (updated && entryInfo.patternValue) {
|
|
291
|
+
if (updated && entryInfo.patternValue && shouldCallUpdated(entryInfo)) {
|
|
292
292
|
updated({
|
|
293
293
|
relativeUrl: entryInfo.relativeUrl,
|
|
294
294
|
type: entryInfo.type,
|
|
295
295
|
patternValue: entryInfo.patternValue,
|
|
296
|
-
mtime: entryInfo.mtimeMs,
|
|
297
|
-
previousMtime: entryInfo.previousInfo.mtimeMs,
|
|
296
|
+
mtime: entryInfo.stat.mtimeMs,
|
|
297
|
+
previousMtime: entryInfo.previousInfo.stat.mtimeMs,
|
|
298
298
|
});
|
|
299
299
|
}
|
|
300
300
|
};
|
|
@@ -302,7 +302,7 @@ export const registerDirectoryLifecycle = (
|
|
|
302
302
|
readdirSync(new URL(sourceUrl)).forEach((entry) => {
|
|
303
303
|
const entryUrl = new URL(entry, sourceUrl).href;
|
|
304
304
|
const entryInfo = readEntryInfo(entryUrl);
|
|
305
|
-
if (entryInfo && entryInfo.patternValue) {
|
|
305
|
+
if (entryInfo.type !== null && entryInfo.patternValue) {
|
|
306
306
|
handleEntryFound(entryInfo, {
|
|
307
307
|
notify: notifyExistent,
|
|
308
308
|
});
|
|
@@ -336,6 +336,20 @@ ${relativeUrls.join("\n")}`,
|
|
|
336
336
|
return tracker.cleanup;
|
|
337
337
|
};
|
|
338
338
|
|
|
339
|
+
const shouldCallUpdated = (entryInfo) => {
|
|
340
|
+
const { stat, previousInfo } = entryInfo;
|
|
341
|
+
if (!stat.atimeMs) {
|
|
342
|
+
return true;
|
|
343
|
+
}
|
|
344
|
+
if (stat.atimeMs < stat.mtimeMs) {
|
|
345
|
+
return true;
|
|
346
|
+
}
|
|
347
|
+
if (stat.mtimeMs > previousInfo.stat.mtimeMs) {
|
|
348
|
+
return true;
|
|
349
|
+
}
|
|
350
|
+
return false;
|
|
351
|
+
};
|
|
352
|
+
|
|
339
353
|
const undefinedOrFunction = (value) => {
|
|
340
354
|
return typeof value === "undefined" || typeof value === "function";
|
|
341
355
|
};
|
|
@@ -47,7 +47,7 @@ export const registerFileLifecycle = (
|
|
|
47
47
|
|
|
48
48
|
const tracker = trackResources();
|
|
49
49
|
|
|
50
|
-
const handleFileFound = ({ existent }) => {
|
|
50
|
+
const handleFileFound = ({ stat, existent }) => {
|
|
51
51
|
const fileMutationStopWatching = watchFileMutation(sourceUrl, {
|
|
52
52
|
updated,
|
|
53
53
|
removed: () => {
|
|
@@ -58,6 +58,7 @@ export const registerFileLifecycle = (
|
|
|
58
58
|
}
|
|
59
59
|
},
|
|
60
60
|
keepProcessAlive,
|
|
61
|
+
stat,
|
|
61
62
|
});
|
|
62
63
|
const fileMutationStopTracking = tracker.registerCleanupCallback(
|
|
63
64
|
fileMutationStopWatching,
|
|
@@ -77,9 +78,9 @@ export const registerFileLifecycle = (
|
|
|
77
78
|
const watchFileAdded = () => {
|
|
78
79
|
const fileCreationStopWatching = watchFileCreation(
|
|
79
80
|
sourceUrl,
|
|
80
|
-
() => {
|
|
81
|
+
(stat) => {
|
|
81
82
|
fileCreationgStopTracking();
|
|
82
|
-
handleFileFound({ existent: false });
|
|
83
|
+
handleFileFound({ stat, existent: false });
|
|
83
84
|
},
|
|
84
85
|
keepProcessAlive,
|
|
85
86
|
);
|
|
@@ -88,8 +89,8 @@ export const registerFileLifecycle = (
|
|
|
88
89
|
);
|
|
89
90
|
};
|
|
90
91
|
|
|
91
|
-
const
|
|
92
|
-
if (
|
|
92
|
+
const { type, stat } = readFileInfo(sourceUrl);
|
|
93
|
+
if (type === null) {
|
|
93
94
|
if (added) {
|
|
94
95
|
watchFileAdded();
|
|
95
96
|
} else {
|
|
@@ -97,8 +98,8 @@ export const registerFileLifecycle = (
|
|
|
97
98
|
`${urlToFileSystemPath(sourceUrl)} must lead to a file, found nothing`,
|
|
98
99
|
);
|
|
99
100
|
}
|
|
100
|
-
} else if (
|
|
101
|
-
handleFileFound({ existent: true });
|
|
101
|
+
} else if (type === "file") {
|
|
102
|
+
handleFileFound({ stat, existent: true });
|
|
102
103
|
} else {
|
|
103
104
|
throw new Error(
|
|
104
105
|
`${urlToFileSystemPath(
|
|
@@ -110,13 +111,19 @@ export const registerFileLifecycle = (
|
|
|
110
111
|
return tracker.cleanup;
|
|
111
112
|
};
|
|
112
113
|
|
|
113
|
-
const
|
|
114
|
+
const readFileInfo = (url) => {
|
|
114
115
|
try {
|
|
115
|
-
const
|
|
116
|
-
return
|
|
116
|
+
const stat = statSync(new URL(url));
|
|
117
|
+
return {
|
|
118
|
+
type: statsToType(stat),
|
|
119
|
+
stat,
|
|
120
|
+
};
|
|
117
121
|
} catch (e) {
|
|
118
122
|
if (e.code === "ENOENT") {
|
|
119
|
-
return
|
|
123
|
+
return {
|
|
124
|
+
type: null,
|
|
125
|
+
stat: null,
|
|
126
|
+
};
|
|
120
127
|
}
|
|
121
128
|
throw e;
|
|
122
129
|
}
|
|
@@ -135,14 +142,15 @@ const watchFileCreation = (source, callback, keepProcessAlive) => {
|
|
|
135
142
|
directoryWatcher.on("change", (eventType, filename) => {
|
|
136
143
|
if (filename && filename !== sourceFilename) return;
|
|
137
144
|
|
|
138
|
-
const type =
|
|
145
|
+
const { type, stat } = readFileInfo(source);
|
|
139
146
|
// ignore if something else with that name gets created
|
|
140
147
|
// we are only interested into files
|
|
141
|
-
if (type !== "file")
|
|
142
|
-
|
|
148
|
+
if (type !== "file") {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
143
151
|
directoryWatcher.close();
|
|
144
152
|
directoryWatcher = undefined;
|
|
145
|
-
callback();
|
|
153
|
+
callback(stat);
|
|
146
154
|
});
|
|
147
155
|
|
|
148
156
|
return () => {
|
|
@@ -154,26 +162,28 @@ const watchFileCreation = (source, callback, keepProcessAlive) => {
|
|
|
154
162
|
|
|
155
163
|
const watchFileMutation = (
|
|
156
164
|
sourceUrl,
|
|
157
|
-
{ updated, removed, keepProcessAlive },
|
|
165
|
+
{ updated, removed, keepProcessAlive, stat },
|
|
158
166
|
) => {
|
|
167
|
+
let prevStat = stat;
|
|
159
168
|
let watcher = createWatcher(urlToFileSystemPath(sourceUrl), {
|
|
160
169
|
persistent: keepProcessAlive,
|
|
161
170
|
});
|
|
162
171
|
|
|
163
172
|
watcher.on("change", () => {
|
|
164
|
-
const
|
|
173
|
+
const { type, stat } = readFileInfo(sourceUrl);
|
|
165
174
|
|
|
166
|
-
if (
|
|
175
|
+
if (type === null) {
|
|
167
176
|
watcher.close();
|
|
168
177
|
watcher = undefined;
|
|
169
178
|
if (removed) {
|
|
170
179
|
removed();
|
|
171
180
|
}
|
|
172
|
-
} else if (
|
|
173
|
-
if (updated) {
|
|
181
|
+
} else if (type === "file") {
|
|
182
|
+
if (updated && shouldCallUpdated(stat, prevStat)) {
|
|
174
183
|
updated();
|
|
175
184
|
}
|
|
176
185
|
}
|
|
186
|
+
prevStat = stat;
|
|
177
187
|
});
|
|
178
188
|
|
|
179
189
|
return () => {
|
|
@@ -182,3 +192,16 @@ const watchFileMutation = (
|
|
|
182
192
|
}
|
|
183
193
|
};
|
|
184
194
|
};
|
|
195
|
+
|
|
196
|
+
const shouldCallUpdated = (stat, prevStat) => {
|
|
197
|
+
if (!stat.atimeMs) {
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
if (stat.atimeMs < stat.mtimeMs) {
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
if (stat.mtimeMs > prevStat.mtimeMs) {
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
return false;
|
|
207
|
+
};
|