@happyvertical/smrt-scanner 0.40.61 → 0.40.63

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/AGENTS.md CHANGED
@@ -22,11 +22,37 @@ executes the source.
22
22
  and asserts every `@smrt()` object reached `dist/manifest.json` (issue #1483).
23
23
  Returns `ok` / `incomplete` / `missing-manifest` / `scan-error` / `skipped`.
24
24
  Driven by `scripts/verify-manifest-completeness.mjs` from `prepack`.
25
+ - `discoverSourceFiles(options)` — shared bounded source-discovery policy used
26
+ by `OxcScanner` and the core manifest preflight.
25
27
  - Types (re-exported from `./types`): `RawClassDefinition`,
26
28
  `RawFieldDefinition`, `RawMethodDefinition`, `ResolvedClassDefinition`,
27
29
  `ScanResults`, `FileScanResult`, `OxcScannerOptions`, `InferredFieldType`,
28
30
  `FieldTypeInference`.
29
31
 
32
+ ## Discovery boundaries
33
+
34
+ File discovery is the difference between a scan that finishes and one that
35
+ exhausts the heap when the scanner is pointed at an application root (#2275):
36
+
37
+ - `dot: true` is set so ignore patterns apply beneath dot directories. Without
38
+ it a `**` cannot cross a dot segment, so `**/node_modules/**` pruned the root
39
+ `node_modules` but nothing under `.svelte-kit/`, `.vercel/`, or `.turbo/`.
40
+ - Mandatory excludes (`**/node_modules/**`, `**/.*/**`, `**/.*`) are unioned
41
+ with the caller's `exclude` and cannot be overridden. `exclude` REPLACES the
42
+ defaults, so every caller that narrowed it had silently reopened
43
+ `node_modules`.
44
+ - `followSymbolicLinks` defaults to `false`. A pnpm `node_modules` is a symlink
45
+ graph with cycles, not a tree, so a link-following walk reaches the same real
46
+ directory once per path leading to it. This drops symlinked *files* as well as
47
+ directories, so pass `followSymbolicLinks: true` for a project that genuinely
48
+ keeps sources behind a link — it is threaded through `smrtPlugin` and
49
+ `ManifestBuilderOptions` for the build path.
50
+ - Patterns are rewritten relative to `cwd` before globbing. Globs match as text,
51
+ so an absolute pattern would hand `**/.*/**` the project's own ancestors and a
52
+ checkout under `~/.worktrees` or `~/.cache` would match nothing at all.
53
+ - `dot: true` would otherwise widen the result to hidden files, so `**/.*` is in
54
+ the mandatory prunes too: hidden files stay out, exactly as before.
55
+
30
56
  ## How It Works
31
57
 
32
58
  1. `fast-glob` finds `.ts` files matching include/exclude patterns.
@@ -43,6 +69,7 @@ executes the source.
43
69
  `parseSource`, `extractSmrtImports`, field/decorator/type extractors).
44
70
  - `src/scanner.ts` — `OxcScanner`: globbing + multi-file orchestration
45
71
  (`scan` / `scanAndResolve`).
72
+ - `src/discovery.ts` — shared bounded glob policy for every scanner entry point.
46
73
  - `src/inheritance-resolver.ts` — `InheritanceResolver`: cross-file inheritance
47
74
  merging.
48
75
  - `src/manifest-adapter.ts` — `ManifestAdapter`: raw → manifest conversion and
@@ -1,7 +1,49 @@
1
+ import { isAbsolute, resolve, sep, win32 } from "node:path";
2
+ import fg from "fast-glob";
1
3
  import { readFileSync } from "node:fs";
2
4
  import { parseSync } from "oxc-parser";
3
- import "node:path";
4
- import fg from "fast-glob";
5
+ //#region src/discovery.ts
6
+ var MANDATORY_DISCOVERY_EXCLUDES = Object.freeze([
7
+ "**/node_modules/**",
8
+ "**/.*/**",
9
+ "**/.*"
10
+ ]);
11
+ async function discoverSourceFiles(options) {
12
+ const cwd = resolve(options.cwd);
13
+ return fg(options.include.map((pattern) => relativeGlobToCwd(pattern, cwd)), {
14
+ cwd,
15
+ ignore: [...options.exclude.map((pattern) => relativeGlobToCwd(pattern, cwd)), ...MANDATORY_DISCOVERY_EXCLUDES],
16
+ absolute: true,
17
+ onlyFiles: true,
18
+ dot: true,
19
+ followSymbolicLinks: options.followSymbolicLinks ?? false
20
+ });
21
+ }
22
+ function relativeGlobToCwd(pattern, cwd) {
23
+ const windowsAbsolute = win32.isAbsolute(pattern);
24
+ if (!isAbsolute(pattern) && !windowsAbsolute) return pattern;
25
+ const cwdVariants = [
26
+ cwd,
27
+ cwd.replaceAll("\\", "/"),
28
+ cwd.replaceAll("/", "\\")
29
+ ];
30
+ for (const prefix of new Set(cwdVariants)) {
31
+ const comparablePattern = windowsAbsolute ? pattern.toLowerCase() : pattern;
32
+ const comparablePrefix = windowsAbsolute ? prefix.toLowerCase() : prefix;
33
+ if (comparablePattern === comparablePrefix) return ".";
34
+ const boundary = pattern.charAt(prefix.length);
35
+ if (comparablePattern.startsWith(comparablePrefix) && (boundary === "/" || boundary === "\\")) {
36
+ const rewritten = pattern.slice(prefix.length + 1);
37
+ return boundary === "\\" ? normalizeGlobSeparators(rewritten, "\\") : rewritten;
38
+ }
39
+ }
40
+ const slashAuthoredWindows = /^[A-Za-z]:\//.test(pattern);
41
+ return windowsAbsolute && !slashAuthoredWindows ? normalizeGlobSeparators(pattern, "\\") : pattern;
42
+ }
43
+ function normalizeGlobSeparators(pattern, pathSeparator = sep) {
44
+ return pathSeparator === "/" ? pattern : pattern.replaceAll(pathSeparator, "/");
45
+ }
46
+ //#endregion
5
47
  //#region src/inheritance-resolver.ts
6
48
  var FRAMEWORK_BASE_CLASSES = /* @__PURE__ */ new Set([
7
49
  "SmrtObject",
@@ -1928,7 +1970,8 @@ var OxcScanner = class {
1928
1970
  baseClasses: options.baseClasses || [],
1929
1971
  includePrivateMethods: options.includePrivateMethods ?? false,
1930
1972
  includeStaticMethods: options.includeStaticMethods ?? true,
1931
- externalManifests: options.externalManifests || /* @__PURE__ */ new Map()
1973
+ externalManifests: options.externalManifests || /* @__PURE__ */ new Map(),
1974
+ followSymbolicLinks: options.followSymbolicLinks ?? false
1932
1975
  };
1933
1976
  this.resolver = new InheritanceResolver({
1934
1977
  baseClasses: this.options.baseClasses,
@@ -2085,15 +2128,34 @@ var OxcScanner = class {
2085
2128
  };
2086
2129
  }
2087
2130
  /**
2088
- * Discover files to scan using fast-glob
2131
+ * Discover files to scan using fast-glob.
2132
+ *
2133
+ * Two settings here decide whether discovery terminates at all when the
2134
+ * scanner is pointed at an application root rather than a package `src/`:
2135
+ *
2136
+ * - `dot: true`. Without it a `**` in an ignore pattern cannot cross a
2137
+ * dot segment, so `**\/node_modules/**` prunes `node_modules` at the root
2138
+ * but NOT `.svelte-kit/…/node_modules` or any other `node_modules` under a
2139
+ * dot directory. Those subtrees were then walked in full and every entry
2140
+ * discarded — unbounded work that could never produce a match.
2141
+ * - `followSymbolicLinks: false`. pnpm materializes `node_modules` as a
2142
+ * symlink graph with cycles, so a link-following walk revisits the same
2143
+ * real directories once per path that reaches them.
2144
+ *
2145
+ * Together they were enough to exhaust a 4 GB heap on a consumer app that
2146
+ * installs the published packages (#2275).
2147
+ *
2148
+ * Patterns are rewritten relative to `cwd` first. fast-glob matches `ignore`
2149
+ * in whatever space the patterns use, so an absolute pattern would hand
2150
+ * `**\/.*\/**` the project's own ancestors — a checkout under `~/.worktrees`
2151
+ * or `~/.cache` would then match nothing at all, silently.
2089
2152
  */
2090
2153
  async discoverFiles() {
2091
- const patterns = this.options.include;
2092
- return await fg(patterns, {
2154
+ return discoverSourceFiles({
2093
2155
  cwd: this.options.cwd,
2094
- ignore: this.options.exclude,
2095
- absolute: true,
2096
- onlyFiles: true
2156
+ include: this.options.include,
2157
+ exclude: this.options.exclude,
2158
+ followSymbolicLinks: this.options.followSymbolicLinks
2097
2159
  });
2098
2160
  }
2099
2161
  /**
@@ -2104,6 +2166,6 @@ var OxcScanner = class {
2104
2166
  }
2105
2167
  };
2106
2168
  //#endregion
2107
- export { parseSource as a, parseFile as i, ManifestAdapter as n, InheritanceResolver as o, extractSmrtImports as r, OxcScanner as t };
2169
+ export { parseSource as a, normalizeGlobSeparators as c, parseFile as i, relativeGlobToCwd as l, ManifestAdapter as n, InheritanceResolver as o, extractSmrtImports as r, discoverSourceFiles as s, OxcScanner as t };
2108
2170
 
2109
- //# sourceMappingURL=scanner-DEGZfoLz.js.map
2171
+ //# sourceMappingURL=scanner-LeMvLJ6X.js.map