1tube 0.1.22 → 0.1.24
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
|
@@ -20,7 +20,11 @@
|
|
|
20
20
|
* tracks it correctly.
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
// Direct `jsr:` specifier (not the `@deno/graph` import-map alias from
|
|
24
|
+
// our own deno.json) so this module loads cleanly when 1tube is
|
|
25
|
+
// consumed from a host project's node_modules — host configs do not
|
|
26
|
+
// mirror our import map. Same convention as every other src/ file.
|
|
27
|
+
import { createGraph } from "jsr:@deno/graph@^0.108";
|
|
24
28
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
25
29
|
|
|
26
30
|
// Local re-export for callers that prefer std/path-style names. Underlying
|
|
@@ -147,42 +147,47 @@ export function createDenoReloadDebouncer(
|
|
|
147
147
|
* precise case — exactly the functions that transitively import the
|
|
148
148
|
* changed file.
|
|
149
149
|
* 2. Files matching `<functionsDir>/<name>/index.ts`: include `<name>`.
|
|
150
|
-
* Catches
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
150
|
+
* Catches the entry's own edits.
|
|
151
|
+
* 3. Path is the directory `<functionsDir>/<name>` itself or any path
|
|
152
|
+
* under it (subtree change). This is necessary for two cases the
|
|
153
|
+
* other rules miss:
|
|
154
|
+
* - **Linux**: `Deno.watchFs` is recursive only over the dirs
|
|
155
|
+
* that existed at start. A *new* function dir reports a single
|
|
156
|
+
* `<functionsDir>/<name>` create event — child file events
|
|
157
|
+
* never fire because inotify doesn't auto-watch the new subdir.
|
|
158
|
+
* - **Windows**: deleting a function dir tree emits dir-path
|
|
159
|
+
* events instead of `index.ts` events.
|
|
160
|
+
* Either way the affected name is the first path component after
|
|
161
|
+
* `functionsDir`. We let `discoverCandidates` filter out junk
|
|
162
|
+
* (e.g. `_shared`) on the reload pass so this rule stays simple
|
|
163
|
+
* and doesn't need the host's knownNames set.
|
|
158
164
|
*/
|
|
159
165
|
export function computeAffected(
|
|
160
166
|
paths: readonly string[],
|
|
161
167
|
depGraph: DepGraph,
|
|
162
|
-
options: { functionsDir?: string
|
|
168
|
+
options: { functionsDir?: string } = {},
|
|
163
169
|
): Set<string> {
|
|
164
170
|
const out = depGraph.affected(paths);
|
|
165
171
|
for (const p of paths) {
|
|
166
172
|
const m = /[\\/]([^\\/]+)[\\/]index\.ts$/.exec(p);
|
|
167
173
|
if (m && m[1]) out.add(m[1]);
|
|
168
174
|
}
|
|
169
|
-
if (options.functionsDir
|
|
175
|
+
if (options.functionsDir) {
|
|
170
176
|
const fnDir = options.functionsDir.replace(/[\\/]$/, "");
|
|
171
|
-
for (const
|
|
172
|
-
//
|
|
173
|
-
//
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}
|
|
177
|
+
for (const p of paths) {
|
|
178
|
+
// Strip the prefix; anything left should look like
|
|
179
|
+
// `/<name>` or `/<name>/<rest>`. Cross-platform: try both
|
|
180
|
+
// separators and accept whichever the OS produced.
|
|
181
|
+
let rest: string | null = null;
|
|
182
|
+
if (p.startsWith(fnDir + "/")) rest = p.slice(fnDir.length + 1);
|
|
183
|
+
else if (p.startsWith(fnDir + "\\")) rest = p.slice(fnDir.length + 1);
|
|
184
|
+
else if (p === fnDir) continue;
|
|
185
|
+
if (rest === null) continue;
|
|
186
|
+
const seg = rest.split(/[\\/]/, 1)[0];
|
|
187
|
+
// Skip private/shared dirs the host already filters out — keeps
|
|
188
|
+
// the affected set tight even before `reload()` runs.
|
|
189
|
+
if (!seg || seg.startsWith("_") || seg.endsWith("_shared")) continue;
|
|
190
|
+
out.add(seg);
|
|
186
191
|
}
|
|
187
192
|
}
|
|
188
193
|
return out;
|
|
@@ -205,10 +210,29 @@ export function createDenoHotReloader(
|
|
|
205
210
|
setTimer: opts.setTimer,
|
|
206
211
|
clearTimer: opts.clearTimer,
|
|
207
212
|
flushFn: async (paths) => {
|
|
208
|
-
const
|
|
213
|
+
const raw = computeAffected(paths, opts.host.depGraph, {
|
|
209
214
|
functionsDir: opts.functionsDir,
|
|
210
|
-
knownNames: opts.host.list(),
|
|
211
215
|
});
|
|
216
|
+
// Filter to names that are either currently loaded or have an
|
|
217
|
+
// `index.ts` on disk right now. This drops spurious entries
|
|
218
|
+
// synthesized from non-function files at the root of
|
|
219
|
+
// `functionsDir` (README.md, .gitignore, …) so we don't spend
|
|
220
|
+
// a reload pass producing an empty summary.
|
|
221
|
+
const known = new Set(opts.host.list());
|
|
222
|
+
const affected = new Set<string>();
|
|
223
|
+
for (const name of raw) {
|
|
224
|
+
if (known.has(name)) {
|
|
225
|
+
affected.add(name);
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
try {
|
|
229
|
+
const indexPath = `${opts.functionsDir}/${name}/index.ts`;
|
|
230
|
+
const stat = await Deno.stat(indexPath);
|
|
231
|
+
if (stat.isFile) affected.add(name);
|
|
232
|
+
} catch {
|
|
233
|
+
// No index.ts → not a function; drop.
|
|
234
|
+
}
|
|
235
|
+
}
|
|
212
236
|
if (affected.size === 0) return;
|
|
213
237
|
const reason = `${affected.size} function(s) changed: ${
|
|
214
238
|
[...affected].sort().join(", ")
|