@flagshark/core 2.0.0 → 2.1.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/README.md +2 -0
- package/dist/config/schema.d.ts +112 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +63 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/detection/detectors/typescript.d.ts.map +1 -1
- package/dist/detection/detectors/typescript.js +41 -0
- package/dist/detection/detectors/typescript.js.map +1 -1
- package/dist/detection/feature-flag.d.ts +28 -0
- package/dist/detection/feature-flag.d.ts.map +1 -1
- package/dist/detection/helpers.d.ts +16 -0
- package/dist/detection/helpers.d.ts.map +1 -1
- package/dist/detection/helpers.js +117 -6
- package/dist/detection/helpers.js.map +1 -1
- package/dist/detection/import-graph.d.ts +234 -0
- package/dist/detection/import-graph.d.ts.map +1 -0
- package/dist/detection/import-graph.js +641 -0
- package/dist/detection/import-graph.js.map +1 -0
- package/dist/detection/interface.d.ts +57 -0
- package/dist/detection/interface.d.ts.map +1 -1
- package/dist/detection/interface.js.map +1 -1
- package/dist/detection/polyglot-analyzer.d.ts +8 -0
- package/dist/detection/polyglot-analyzer.d.ts.map +1 -1
- package/dist/detection/polyglot-analyzer.js +2 -0
- package/dist/detection/polyglot-analyzer.js.map +1 -1
- package/dist/detection/tree-sitter/engine.d.ts.map +1 -1
- package/dist/detection/tree-sitter/engine.js +62 -15
- package/dist/detection/tree-sitter/engine.js.map +1 -1
- package/dist/detection/tree-sitter/parser-cache.d.ts +20 -0
- package/dist/detection/tree-sitter/parser-cache.d.ts.map +1 -1
- package/dist/detection/tree-sitter/parser-cache.js +32 -1
- package/dist/detection/tree-sitter/parser-cache.js.map +1 -1
- package/dist/output/json.d.ts.map +1 -1
- package/dist/output/json.js +28 -0
- package/dist/output/json.js.map +1 -1
- package/dist/output/markdown.d.ts.map +1 -1
- package/dist/output/markdown.js +47 -1
- package/dist/output/markdown.js.map +1 -1
- package/dist/output/text.d.ts.map +1 -1
- package/dist/output/text.js +89 -0
- package/dist/output/text.js.map +1 -1
- package/dist/providers/cross-reference.d.ts +36 -2
- package/dist/providers/cross-reference.d.ts.map +1 -1
- package/dist/providers/cross-reference.js +102 -7
- package/dist/providers/cross-reference.js.map +1 -1
- package/dist/providers/interface.d.ts +116 -2
- package/dist/providers/interface.d.ts.map +1 -1
- package/dist/providers/launchdarkly/client.d.ts +12 -0
- package/dist/providers/launchdarkly/client.d.ts.map +1 -1
- package/dist/providers/launchdarkly/client.js +243 -24
- package/dist/providers/launchdarkly/client.js.map +1 -1
- package/dist/providers/launchdarkly/types.d.ts +318 -0
- package/dist/providers/launchdarkly/types.d.ts.map +1 -1
- package/dist/providers/launchdarkly/types.js +82 -0
- package/dist/providers/launchdarkly/types.js.map +1 -1
- package/dist/providers/orchestrate.d.ts +34 -2
- package/dist/providers/orchestrate.d.ts.map +1 -1
- package/dist/providers/orchestrate.js +59 -7
- package/dist/providers/orchestrate.js.map +1 -1
- package/dist/scan-repo.d.ts +28 -0
- package/dist/scan-repo.d.ts.map +1 -1
- package/dist/scan-repo.js +290 -4
- package/dist/scan-repo.js.map +1 -1
- package/dist/staleness.d.ts +31 -1
- package/dist/staleness.d.ts.map +1 -1
- package/dist/staleness.js +66 -10
- package/dist/staleness.js.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,641 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight import-graph builder for TS/JS files.
|
|
3
|
+
*
|
|
4
|
+
* Goal: extend the existing "file imports a known SDK" detection gate to cover
|
|
5
|
+
* the common case where consumer files reach the SDK through a local wrapper —
|
|
6
|
+
* an internal `flag-resolver.ts`, a Pinia store, a custom React hook, a re-export
|
|
7
|
+
* barrel, etc. Without this, real codebases that hide the SDK behind an
|
|
8
|
+
* abstraction silently report 0 flags (see the pre-launch shakedown notes:
|
|
9
|
+
* Unleash at 4 of 62, n8n at 0 of many).
|
|
10
|
+
*
|
|
11
|
+
* Design — three deliberate compromises in service of "ship soon and don't add
|
|
12
|
+
* false positives":
|
|
13
|
+
*
|
|
14
|
+
* 1. **Regex import extraction, not tree-sitter.** The existing analyzer
|
|
15
|
+
* already parses each file once for flag detection; running a second
|
|
16
|
+
* tree-sitter pass for imports would roughly double scan time on a large
|
|
17
|
+
* monorepo. Three regexes cover ESM static imports, CJS require(), and
|
|
18
|
+
* dynamic import() with >95% coverage of real-world syntax. The misses
|
|
19
|
+
* (heavily multi-line imports, computed-string specifiers, etc.) only
|
|
20
|
+
* cost us some recall — they never add false positives because the gate
|
|
21
|
+
* still requires a *real* SDK string match downstream.
|
|
22
|
+
*
|
|
23
|
+
* 2. **Relative-path resolution only.** TypeScript path aliases
|
|
24
|
+
* (`@/foo` via tsconfig.paths), workspace `@scope/pkg` resolution, and
|
|
25
|
+
* package.json `exports` are out of scope. A user with path aliases will
|
|
26
|
+
* hit the same blind spot as today; we document it. The right fix is to
|
|
27
|
+
* read tsconfig.json and apply paths — separate workstream, not a Show HN
|
|
28
|
+
* blocker.
|
|
29
|
+
*
|
|
30
|
+
* 3. **Reverse-reachability BFS from SDK-importing seeds.** We propagate
|
|
31
|
+
* SDK provenance *away* from the SDK importers. A file is "in scope" iff
|
|
32
|
+
* it transitively imports something that imports an SDK. Cycle-safe via
|
|
33
|
+
* a "did the set actually grow?" check before requeueing — bounded
|
|
34
|
+
* O(edges × seeds) in the worst case.
|
|
35
|
+
*
|
|
36
|
+
* The output is consumed by PolyglotAnalyzer, which uses it to mark
|
|
37
|
+
* wrapper-consumer files as SDK-positive *for the gating step only* — actual
|
|
38
|
+
* flag-key extraction still goes through the same per-provider patterns, so
|
|
39
|
+
* precision stays the same as direct-import detection.
|
|
40
|
+
*/
|
|
41
|
+
import * as fs from 'node:fs';
|
|
42
|
+
import path from 'node:path';
|
|
43
|
+
import { Languages } from './interface.js';
|
|
44
|
+
// -- Import-extraction regexes --------------------------------------------------
|
|
45
|
+
//
|
|
46
|
+
// All three patterns capture the bare module specifier in group 1. Anchored
|
|
47
|
+
// loosely enough to handle whitespace variations but not so loosely that they
|
|
48
|
+
// match inside strings or comments — both forms have a leading non-word boundary
|
|
49
|
+
// (or start-of-line, for ESM) before the keyword.
|
|
50
|
+
/**
|
|
51
|
+
* ESM static imports. Matches:
|
|
52
|
+
* import 'foo'
|
|
53
|
+
* import x from 'foo'
|
|
54
|
+
* import { a, b } from 'foo'
|
|
55
|
+
* import * as x from 'foo'
|
|
56
|
+
* import x, { a } from 'foo'
|
|
57
|
+
* import type { a } from 'foo'
|
|
58
|
+
* import type * as x from 'foo'
|
|
59
|
+
*
|
|
60
|
+
* The optional `\s+...\s+from\s+` clause uses a lazy quantifier so it doesn't
|
|
61
|
+
* greedily swallow a no-from `import 'foo'`. Multi-line imports (newlines
|
|
62
|
+
* inside the import clause) are a known miss — `[^'"`;\n]*` excludes newlines
|
|
63
|
+
* to keep matching linear-time. In practice those are rare outside
|
|
64
|
+
* auto-generated barrels.
|
|
65
|
+
*/
|
|
66
|
+
const ESM_IMPORT_RE = /^[ \t]*import\s*(?:\s+type)?\s*(?:[^'"`;\n]*?\s+from\s+)?['"`]([^'"`]+)['"`]/gm;
|
|
67
|
+
/**
|
|
68
|
+
* CJS require(). Matches:
|
|
69
|
+
* const x = require('foo')
|
|
70
|
+
* require('foo')
|
|
71
|
+
*
|
|
72
|
+
* The lookbehind `(?<![.\w$])` blocks `foo.require('bar')` and
|
|
73
|
+
* `myRequire('bar')` — anything where `require` is part of a longer identifier
|
|
74
|
+
* or a member-expression property name.
|
|
75
|
+
*/
|
|
76
|
+
const REQUIRE_RE = /(?<![.\w$])require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
77
|
+
/**
|
|
78
|
+
* Dynamic ESM imports. Matches:
|
|
79
|
+
* import('foo')
|
|
80
|
+
* await import('foo')
|
|
81
|
+
*
|
|
82
|
+
* Same lookbehind guard as REQUIRE_RE to avoid `obj.import('foo')`.
|
|
83
|
+
*/
|
|
84
|
+
const DYNAMIC_IMPORT_RE = /(?<![.\w$])import\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
85
|
+
/**
|
|
86
|
+
* Python `from X import Y` matcher. `X` can be:
|
|
87
|
+
* - a dotted module path (`posthog.client`)
|
|
88
|
+
* - a relative path (`.utils`, `..lib.flags`, `...common.feature_flags`)
|
|
89
|
+
*
|
|
90
|
+
* Captures group 1 = the module path (including leading dots if any).
|
|
91
|
+
* Names after `import` are intentionally not captured — for the import-graph
|
|
92
|
+
* we care about which MODULE was reached, not which names were brought in.
|
|
93
|
+
*
|
|
94
|
+
* Anchored to line start (after optional indentation) to skip `from` keywords
|
|
95
|
+
* that appear mid-expression (e.g. in docstrings or string literals).
|
|
96
|
+
*/
|
|
97
|
+
const PY_FROM_IMPORT_RE = /^[ \t]*from\s+(\.*[\w.]+)\s+import\s+/gm;
|
|
98
|
+
/**
|
|
99
|
+
* Python bare `import X` / `import X as Y` matcher (top-level only, never
|
|
100
|
+
* `if cond: import X` because conditional imports almost always indicate
|
|
101
|
+
* fallback paths we shouldn't follow as the primary edge).
|
|
102
|
+
*
|
|
103
|
+
* Captures the module path — comma-separated multi-imports (`import a, b`)
|
|
104
|
+
* are uncommon in real code; we handle them by running this regex once and
|
|
105
|
+
* splitting the capture on `,` post-hoc.
|
|
106
|
+
*/
|
|
107
|
+
const PY_IMPORT_RE = /^[ \t]*import\s+([\w.]+(?:\s*,\s*[\w.]+)*)/gm;
|
|
108
|
+
/**
|
|
109
|
+
* Extracts every module specifier mentioned in a TS/JS file.
|
|
110
|
+
*
|
|
111
|
+
* @returns a deduplicated array of specifier strings, in the order first seen.
|
|
112
|
+
* Order is not load-bearing for the graph algorithm but makes test fixtures
|
|
113
|
+
* readable.
|
|
114
|
+
*/
|
|
115
|
+
export function extractImports(content) {
|
|
116
|
+
const seen = new Set();
|
|
117
|
+
const out = [];
|
|
118
|
+
const collect = (re) => {
|
|
119
|
+
// Reset state on the shared RegExp — we use the /g flag for exec loops.
|
|
120
|
+
re.lastIndex = 0;
|
|
121
|
+
let m;
|
|
122
|
+
while ((m = re.exec(content)) !== null) {
|
|
123
|
+
const spec = m[1];
|
|
124
|
+
if (!seen.has(spec)) {
|
|
125
|
+
seen.add(spec);
|
|
126
|
+
out.push(spec);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
collect(ESM_IMPORT_RE);
|
|
131
|
+
collect(REQUIRE_RE);
|
|
132
|
+
collect(DYNAMIC_IMPORT_RE);
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Extracts every module specifier mentioned in a Python file. Returns each
|
|
137
|
+
* specifier verbatim (including leading dots for relative imports). The
|
|
138
|
+
* graph's seed-matching logic compares the bare module name (everything
|
|
139
|
+
* before the first dot, e.g. `posthog` from `posthog.client`) against the
|
|
140
|
+
* SDK seed list.
|
|
141
|
+
*
|
|
142
|
+
* Multi-import lines like `import a, b, c` are split into individual
|
|
143
|
+
* specifiers; deduplicated within a file.
|
|
144
|
+
*/
|
|
145
|
+
export function extractPythonImports(content) {
|
|
146
|
+
const seen = new Set();
|
|
147
|
+
const out = [];
|
|
148
|
+
const push = (spec) => {
|
|
149
|
+
const trimmed = spec.trim();
|
|
150
|
+
if (trimmed.length === 0 || seen.has(trimmed))
|
|
151
|
+
return;
|
|
152
|
+
seen.add(trimmed);
|
|
153
|
+
out.push(trimmed);
|
|
154
|
+
};
|
|
155
|
+
PY_FROM_IMPORT_RE.lastIndex = 0;
|
|
156
|
+
let m;
|
|
157
|
+
while ((m = PY_FROM_IMPORT_RE.exec(content)) !== null)
|
|
158
|
+
push(m[1]);
|
|
159
|
+
PY_IMPORT_RE.lastIndex = 0;
|
|
160
|
+
while ((m = PY_IMPORT_RE.exec(content)) !== null) {
|
|
161
|
+
// `import a, b, c` -- split the captured run on commas.
|
|
162
|
+
for (const part of m[1].split(','))
|
|
163
|
+
push(part);
|
|
164
|
+
}
|
|
165
|
+
return out;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Resolves a Python import specifier to a file path that exists in
|
|
169
|
+
* `fileSet`. Python relative imports use dot notation rather than `./`:
|
|
170
|
+
* - `from . import x` → same package as importer
|
|
171
|
+
* - `from .utils import x` → sibling module `utils` in same package
|
|
172
|
+
* - `from ..lib import x` → parent package's `lib`
|
|
173
|
+
* - `from .. import x` → parent package's `__init__.py`
|
|
174
|
+
*
|
|
175
|
+
* Absolute imports (`from posthog.client import x`) are NOT resolved into
|
|
176
|
+
* the file map — they reference installed packages outside the repo. Those
|
|
177
|
+
* get matched against the SDK seed list separately.
|
|
178
|
+
*
|
|
179
|
+
* Returns null for absolute imports or unresolvable paths.
|
|
180
|
+
*/
|
|
181
|
+
export function resolvePythonImport(importerPath, specifier, fileSet) {
|
|
182
|
+
// Count leading dots — that's the package walk depth (one dot = same
|
|
183
|
+
// package, two = parent, three = grandparent, etc.). The remaining
|
|
184
|
+
// dotted name is the module path under that package.
|
|
185
|
+
let dots = 0;
|
|
186
|
+
while (dots < specifier.length && specifier[dots] === '.')
|
|
187
|
+
dots++;
|
|
188
|
+
if (dots === 0)
|
|
189
|
+
return null; // absolute import — see SDK seed matching upstream
|
|
190
|
+
const importerDir = path.dirname(importerPath);
|
|
191
|
+
// First dot is "same dir", each subsequent dot walks up one level.
|
|
192
|
+
let baseDir = importerDir;
|
|
193
|
+
for (let i = 1; i < dots; i++)
|
|
194
|
+
baseDir = path.dirname(baseDir);
|
|
195
|
+
const rest = specifier.slice(dots); // e.g. "utils.helpers" or ""
|
|
196
|
+
if (rest.length === 0) {
|
|
197
|
+
// `from . import x` -- target is the package's __init__.py.
|
|
198
|
+
const candidate = path.join(baseDir, '__init__.py');
|
|
199
|
+
return fileSet.has(candidate) ? candidate : null;
|
|
200
|
+
}
|
|
201
|
+
// Convert "utils.helpers" to "utils/helpers" then try both `.py` and
|
|
202
|
+
// `/__init__.py` forms (Python packages vs modules).
|
|
203
|
+
const segments = rest.split('.').filter((s) => s.length > 0);
|
|
204
|
+
const moduleBase = path.join(baseDir, ...segments);
|
|
205
|
+
const candidateModule = moduleBase + '.py';
|
|
206
|
+
if (fileSet.has(candidateModule))
|
|
207
|
+
return candidateModule;
|
|
208
|
+
const candidatePackage = path.join(moduleBase, '__init__.py');
|
|
209
|
+
if (fileSet.has(candidatePackage))
|
|
210
|
+
return candidatePackage;
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
// -- Path resolution ----------------------------------------------------------
|
|
214
|
+
const TS_JS_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.mts', '.cts'];
|
|
215
|
+
/**
|
|
216
|
+
* Finds the nearest tsconfig.json (or jsconfig.json) at or above `root` and
|
|
217
|
+
* parses `compilerOptions.baseUrl` + `compilerOptions.paths`. Returns null
|
|
218
|
+
* if no config exists, the config has no path aliases, or the file fails
|
|
219
|
+
* to parse.
|
|
220
|
+
*
|
|
221
|
+
* Intentional limitations (documented so the recall ceiling is honest):
|
|
222
|
+
* - We do NOT follow `extends` chains. A tsconfig that inherits aliases
|
|
223
|
+
* from a parent project won't have them resolved here. Real fix would
|
|
224
|
+
* require a recursive resolver matching tsc's actual behaviour.
|
|
225
|
+
* - We only look at the first matching tsconfig walking up from `root`.
|
|
226
|
+
* Nested workspaces with distinct tsconfigs per package aren't handled
|
|
227
|
+
* specially — the outermost one wins. Sufficient for the typical
|
|
228
|
+
* "alias is in repo-root tsconfig" pattern.
|
|
229
|
+
*/
|
|
230
|
+
export function loadTsconfigAliases(root) {
|
|
231
|
+
// Walk up from `root` looking for tsconfig.json, then jsconfig.json.
|
|
232
|
+
// Stop at the filesystem root. Bound the loop so a pathological setup
|
|
233
|
+
// can't hang us — 32 levels is well past any realistic monorepo depth.
|
|
234
|
+
let dir = path.resolve(root);
|
|
235
|
+
for (let i = 0; i < 32; i++) {
|
|
236
|
+
for (const name of ['tsconfig.json', 'jsconfig.json']) {
|
|
237
|
+
const candidate = path.join(dir, name);
|
|
238
|
+
if (fs.existsSync(candidate)) {
|
|
239
|
+
const parsed = readTsconfigJson(candidate);
|
|
240
|
+
if (parsed?.paths)
|
|
241
|
+
return parsed;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
const parent = path.dirname(dir);
|
|
245
|
+
if (parent === dir)
|
|
246
|
+
break;
|
|
247
|
+
dir = parent;
|
|
248
|
+
}
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Parses a JSONC tsconfig file (allows `//` line comments and `/* *\/` block
|
|
253
|
+
* comments — tsc accepts both, JSON.parse does not). The comment stripper is
|
|
254
|
+
* intentionally minimal: it doesn't try to be perfect inside string values,
|
|
255
|
+
* just inside the structural JSON. In practice tsconfig.json string values
|
|
256
|
+
* rarely contain comment-like text (`http://...` paths are URLs, not
|
|
257
|
+
* comments — handled below) so this works for the long tail.
|
|
258
|
+
*/
|
|
259
|
+
function readTsconfigJson(file) {
|
|
260
|
+
let raw;
|
|
261
|
+
try {
|
|
262
|
+
raw = fs.readFileSync(file, 'utf-8');
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
// Strip /* ... */ block comments and // line comments outside strings.
|
|
268
|
+
// We walk the file once, tracking whether we're inside a "..." string —
|
|
269
|
+
// this avoids false-stripping `://` from a URL value, which a naive regex
|
|
270
|
+
// would mangle.
|
|
271
|
+
const stripped = stripJsoncComments(raw);
|
|
272
|
+
let parsed;
|
|
273
|
+
try {
|
|
274
|
+
parsed = JSON.parse(stripped);
|
|
275
|
+
}
|
|
276
|
+
catch {
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
const co = parsed.compilerOptions;
|
|
280
|
+
if (!co?.paths || Object.keys(co.paths).length === 0)
|
|
281
|
+
return null;
|
|
282
|
+
const baseUrl = path.resolve(path.dirname(file), co.baseUrl ?? '.');
|
|
283
|
+
const paths = new Map();
|
|
284
|
+
for (const [alias, targets] of Object.entries(co.paths)) {
|
|
285
|
+
if (Array.isArray(targets))
|
|
286
|
+
paths.set(alias, targets);
|
|
287
|
+
}
|
|
288
|
+
return { baseUrl, paths };
|
|
289
|
+
}
|
|
290
|
+
function stripJsoncComments(src) {
|
|
291
|
+
let out = '';
|
|
292
|
+
let i = 0;
|
|
293
|
+
let inString = false;
|
|
294
|
+
while (i < src.length) {
|
|
295
|
+
const ch = src[i];
|
|
296
|
+
if (inString) {
|
|
297
|
+
out += ch;
|
|
298
|
+
if (ch === '\\' && i + 1 < src.length) {
|
|
299
|
+
out += src[i + 1];
|
|
300
|
+
i += 2;
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
if (ch === '"')
|
|
304
|
+
inString = false;
|
|
305
|
+
i++;
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
if (ch === '"') {
|
|
309
|
+
inString = true;
|
|
310
|
+
out += ch;
|
|
311
|
+
i++;
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
if (ch === '/' && src[i + 1] === '/') {
|
|
315
|
+
// Line comment — skip to next newline.
|
|
316
|
+
while (i < src.length && src[i] !== '\n')
|
|
317
|
+
i++;
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
if (ch === '/' && src[i + 1] === '*') {
|
|
321
|
+
// Block comment — skip to closing */.
|
|
322
|
+
i += 2;
|
|
323
|
+
while (i < src.length - 1 && !(src[i] === '*' && src[i + 1] === '/'))
|
|
324
|
+
i++;
|
|
325
|
+
i += 2;
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
out += ch;
|
|
329
|
+
i++;
|
|
330
|
+
}
|
|
331
|
+
return out;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Tries to apply tsconfig path aliases to a bare-spec import. Returns the
|
|
335
|
+
* resolved absolute file path (if it exists in `fileSet`) or null.
|
|
336
|
+
*
|
|
337
|
+
* Two alias shapes are supported, matching tsc:
|
|
338
|
+
* - Wildcard: key ends with `/*`, target ends with `/*`. The portion
|
|
339
|
+
* after the alias prefix is substituted into the target wildcard.
|
|
340
|
+
* Example: alias `@/*` → `src/*`; specifier `@/lib/foo` resolves to
|
|
341
|
+
* `<baseUrl>/src/lib/foo`.
|
|
342
|
+
* - Exact: no `*`. The specifier matches the alias exactly and resolves
|
|
343
|
+
* to the literal target.
|
|
344
|
+
*/
|
|
345
|
+
export function resolveAliasedImport(specifier, aliases, fileSet) {
|
|
346
|
+
for (const [alias, targets] of aliases.paths) {
|
|
347
|
+
if (alias.endsWith('/*')) {
|
|
348
|
+
const prefix = alias.slice(0, -2) + '/';
|
|
349
|
+
// `@/` must be matched as a prefix; `@/lib/foo` matches `@/*`.
|
|
350
|
+
// Edge case: an alias key like `@/*` should also match `@/lib`
|
|
351
|
+
// without the trailing slash if the user wrote `@/lib` not `@/lib/`.
|
|
352
|
+
// The slash is part of the prefix, so `@/lib` doesn't start with
|
|
353
|
+
// `@//` — handle the slash-less prefix separately.
|
|
354
|
+
const dotPrefix = alias.slice(0, -2); // "@"
|
|
355
|
+
if (!specifier.startsWith(prefix) && specifier !== dotPrefix)
|
|
356
|
+
continue;
|
|
357
|
+
const rest = specifier.slice(prefix.length);
|
|
358
|
+
for (const target of targets) {
|
|
359
|
+
if (!target.endsWith('/*'))
|
|
360
|
+
continue;
|
|
361
|
+
const targetPrefix = target.slice(0, -2);
|
|
362
|
+
const resolved = path.resolve(aliases.baseUrl, targetPrefix, rest);
|
|
363
|
+
const found = tryResolveExisting(resolved, fileSet);
|
|
364
|
+
if (found)
|
|
365
|
+
return found;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
else if (alias === specifier) {
|
|
369
|
+
for (const target of targets) {
|
|
370
|
+
const resolved = path.resolve(aliases.baseUrl, target);
|
|
371
|
+
const found = tryResolveExisting(resolved, fileSet);
|
|
372
|
+
if (found)
|
|
373
|
+
return found;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
return null;
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Given a resolved path (no extension), tries the same exact-then-extension-
|
|
381
|
+
* then-/index.* lookup that resolveImportPath does for relative imports.
|
|
382
|
+
* Factored out so both code paths agree on what "exists" means.
|
|
383
|
+
*/
|
|
384
|
+
function tryResolveExisting(resolved, fileSet) {
|
|
385
|
+
if (fileSet.has(resolved))
|
|
386
|
+
return resolved;
|
|
387
|
+
for (const ext of TS_JS_EXTENSIONS) {
|
|
388
|
+
if (fileSet.has(resolved + ext))
|
|
389
|
+
return resolved + ext;
|
|
390
|
+
}
|
|
391
|
+
for (const ext of TS_JS_EXTENSIONS) {
|
|
392
|
+
const candidate = path.join(resolved, `index${ext}`);
|
|
393
|
+
if (fileSet.has(candidate))
|
|
394
|
+
return candidate;
|
|
395
|
+
}
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Resolves a relative or absolute import specifier to a file path that exists
|
|
400
|
+
* in `fileSet`. Returns null for bare specifiers (unless `aliases` provided
|
|
401
|
+
* and the specifier matches an alias) or unresolvable paths.
|
|
402
|
+
*
|
|
403
|
+
* Resolution order matches Node + TS behavior closely enough for our purposes:
|
|
404
|
+
* 1. Path aliases (when `aliases` provided) — `@/foo` → `src/foo`.
|
|
405
|
+
* 2. Exact match (`./foo.ts`).
|
|
406
|
+
* 3. With each candidate extension (`./foo` → `./foo.ts`).
|
|
407
|
+
* 4. As a directory with `index.<ext>` (`./foo` → `./foo/index.ts`).
|
|
408
|
+
* 5. TS-emitted `.js` rewritten to `.ts` (`./foo.js` → `./foo.ts`), which
|
|
409
|
+
* handles the verbatimModuleSyntax / NodeNext convention where TS source
|
|
410
|
+
* writes `.js` but the actual file is `.ts`. Same for `.jsx`/`.tsx`.
|
|
411
|
+
*/
|
|
412
|
+
export function resolveImportPath(importerPath, specifier, fileSet, aliases) {
|
|
413
|
+
// Try path aliases first — they win over both relative and bare interpretation.
|
|
414
|
+
// A monorepo's `@/foo` is conceptually a re-mapping, not a relative path,
|
|
415
|
+
// so it gets the highest-priority resolution attempt.
|
|
416
|
+
if (aliases) {
|
|
417
|
+
const aliased = resolveAliasedImport(specifier, aliases, fileSet);
|
|
418
|
+
if (aliased)
|
|
419
|
+
return aliased;
|
|
420
|
+
}
|
|
421
|
+
if (!specifier.startsWith('./') && !specifier.startsWith('../') && !specifier.startsWith('/')) {
|
|
422
|
+
return null;
|
|
423
|
+
}
|
|
424
|
+
const importerDir = path.dirname(importerPath);
|
|
425
|
+
const absSpecifier = path.resolve(importerDir, specifier);
|
|
426
|
+
// 1. Exact match
|
|
427
|
+
if (fileSet.has(absSpecifier))
|
|
428
|
+
return absSpecifier;
|
|
429
|
+
// 2. + extension
|
|
430
|
+
for (const ext of TS_JS_EXTENSIONS) {
|
|
431
|
+
const candidate = absSpecifier + ext;
|
|
432
|
+
if (fileSet.has(candidate))
|
|
433
|
+
return candidate;
|
|
434
|
+
}
|
|
435
|
+
// 3. /index.<ext>
|
|
436
|
+
for (const ext of TS_JS_EXTENSIONS) {
|
|
437
|
+
const candidate = path.join(absSpecifier, `index${ext}`);
|
|
438
|
+
if (fileSet.has(candidate))
|
|
439
|
+
return candidate;
|
|
440
|
+
}
|
|
441
|
+
// 4. TS source convention: import './foo.js' → real file is './foo.ts' / './foo.tsx'.
|
|
442
|
+
// Same for .jsx → .tsx, .mjs → .mts, .cjs → .cts.
|
|
443
|
+
const emittedToSourceExt = {
|
|
444
|
+
'.js': ['.ts', '.tsx'],
|
|
445
|
+
'.jsx': ['.tsx', '.jsx'],
|
|
446
|
+
'.mjs': ['.mts', '.mjs'],
|
|
447
|
+
'.cjs': ['.cts', '.cjs'],
|
|
448
|
+
};
|
|
449
|
+
const ext = path.extname(absSpecifier);
|
|
450
|
+
const replacements = emittedToSourceExt[ext];
|
|
451
|
+
if (replacements) {
|
|
452
|
+
const base = absSpecifier.slice(0, absSpecifier.length - ext.length);
|
|
453
|
+
for (const r of replacements) {
|
|
454
|
+
const candidate = base + r;
|
|
455
|
+
if (fileSet.has(candidate))
|
|
456
|
+
return candidate;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
return null;
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Builds the transitive SDK-reach map for a set of TS/JS files.
|
|
463
|
+
*
|
|
464
|
+
* Algorithm:
|
|
465
|
+
* 1. Walk every TS/JS file, extract module specifiers.
|
|
466
|
+
* 2. For each specifier: if it's a seed SDK → record direct SDK reach;
|
|
467
|
+
* if it's a relative path that resolves in the file map → add forward edge.
|
|
468
|
+
* 3. Build the reverse adjacency map (target → importers).
|
|
469
|
+
* 4. Seed the worklist with every directly-importing file. BFS outward
|
|
470
|
+
* through the reverse graph, propagating each importer's SDK set
|
|
471
|
+
* (union of all reachable importees). Requeue only when a set actually
|
|
472
|
+
* grew — this terminates on every cyclic import graph.
|
|
473
|
+
*/
|
|
474
|
+
export function buildImportGraph(files, opts) {
|
|
475
|
+
const fileSet = new Set();
|
|
476
|
+
for (const fp of files.keys()) {
|
|
477
|
+
if (opts.isTsJs(fp))
|
|
478
|
+
fileSet.add(fp);
|
|
479
|
+
}
|
|
480
|
+
const forward = new Map();
|
|
481
|
+
const directSdks = new Map();
|
|
482
|
+
let edgesResolved = 0;
|
|
483
|
+
let edgesUnresolved = 0;
|
|
484
|
+
for (const [filePath, content] of files) {
|
|
485
|
+
if (!fileSet.has(filePath))
|
|
486
|
+
continue;
|
|
487
|
+
// Dispatch extraction and resolution by file extension. Python is the
|
|
488
|
+
// only added language for now; Go has module-path complications (no
|
|
489
|
+
// relative imports — every Go import is a module path) that need a
|
|
490
|
+
// separate design pass. See B4 in the bug inventory.
|
|
491
|
+
const python = isPythonFile(filePath);
|
|
492
|
+
const specs = python ? extractPythonImports(content) : extractImports(content);
|
|
493
|
+
if (specs.length === 0)
|
|
494
|
+
continue;
|
|
495
|
+
const fileImports = new Set();
|
|
496
|
+
const fileSdks = new Set();
|
|
497
|
+
for (const spec of specs) {
|
|
498
|
+
// Seed SDK match. Python's matching is dotted (`posthog.client`
|
|
499
|
+
// starts with `posthog.`); TS/JS is path-style (`unleash-client/lib/x`
|
|
500
|
+
// starts with `unleash-client/`). Both forms reduce to "specifier
|
|
501
|
+
// equals seed OR specifier starts with seed + sep". We pick the
|
|
502
|
+
// separator per-language.
|
|
503
|
+
const sep = python ? '.' : '/';
|
|
504
|
+
for (const sdk of opts.seedSdkPatterns) {
|
|
505
|
+
if (spec === sdk || spec.startsWith(sdk + sep)) {
|
|
506
|
+
fileSdks.add(sdk);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
// Resolve to a file in our scan set.
|
|
510
|
+
if (python) {
|
|
511
|
+
// Python relative imports start with one or more dots.
|
|
512
|
+
if (spec.startsWith('.')) {
|
|
513
|
+
const target = resolvePythonImport(filePath, spec, fileSet);
|
|
514
|
+
if (target) {
|
|
515
|
+
fileImports.add(target);
|
|
516
|
+
edgesResolved++;
|
|
517
|
+
}
|
|
518
|
+
else {
|
|
519
|
+
edgesUnresolved++;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
// Absolute Python imports never resolve into the file map (they
|
|
523
|
+
// reference installed packages); SDK seed matching above catches
|
|
524
|
+
// the ones we care about.
|
|
525
|
+
}
|
|
526
|
+
else {
|
|
527
|
+
// TS/JS: relative or potentially-aliased bare specifier.
|
|
528
|
+
const isRelative = spec.startsWith('./') || spec.startsWith('../') || spec.startsWith('/');
|
|
529
|
+
if (isRelative || opts.aliases) {
|
|
530
|
+
const target = resolveImportPath(filePath, spec, fileSet, opts.aliases);
|
|
531
|
+
if (target) {
|
|
532
|
+
fileImports.add(target);
|
|
533
|
+
edgesResolved++;
|
|
534
|
+
}
|
|
535
|
+
else if (isRelative) {
|
|
536
|
+
// Only count un-resolved RELATIVE edges as misses — bare specs
|
|
537
|
+
// that don't match an alias aren't expected to resolve and
|
|
538
|
+
// shouldn't pollute the stat.
|
|
539
|
+
edgesUnresolved++;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
if (fileImports.size > 0)
|
|
545
|
+
forward.set(filePath, fileImports);
|
|
546
|
+
if (fileSdks.size > 0)
|
|
547
|
+
directSdks.set(filePath, fileSdks);
|
|
548
|
+
}
|
|
549
|
+
// Reverse adjacency: for each "imported file", who imports it?
|
|
550
|
+
const reverse = new Map();
|
|
551
|
+
for (const [importer, targets] of forward) {
|
|
552
|
+
for (const target of targets) {
|
|
553
|
+
let importers = reverse.get(target);
|
|
554
|
+
if (!importers) {
|
|
555
|
+
importers = new Set();
|
|
556
|
+
reverse.set(target, importers);
|
|
557
|
+
}
|
|
558
|
+
importers.add(importer);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
// BFS the reverse graph from every direct-SDK file, propagating its SDK set
|
|
562
|
+
// up the import chain. The propagation is monotonic: a file's SDK set only
|
|
563
|
+
// grows, never shrinks. We requeue only when growth happens, so the algorithm
|
|
564
|
+
// terminates in O(edges × |seed-sdks|) even with cyclic imports.
|
|
565
|
+
const transitiveSdks = new Map();
|
|
566
|
+
for (const [file, sdks] of directSdks) {
|
|
567
|
+
transitiveSdks.set(file, new Set(sdks));
|
|
568
|
+
}
|
|
569
|
+
const worklist = [...directSdks.keys()];
|
|
570
|
+
while (worklist.length > 0) {
|
|
571
|
+
const file = worklist.shift();
|
|
572
|
+
const sdksOfFile = transitiveSdks.get(file);
|
|
573
|
+
/* c8 ignore next -- defensive; file is only added to worklist when its sdk set exists */
|
|
574
|
+
if (!sdksOfFile)
|
|
575
|
+
continue;
|
|
576
|
+
const importers = reverse.get(file);
|
|
577
|
+
if (!importers)
|
|
578
|
+
continue;
|
|
579
|
+
for (const importer of importers) {
|
|
580
|
+
let importerSdks = transitiveSdks.get(importer);
|
|
581
|
+
if (!importerSdks) {
|
|
582
|
+
importerSdks = new Set();
|
|
583
|
+
transitiveSdks.set(importer, importerSdks);
|
|
584
|
+
}
|
|
585
|
+
let grew = false;
|
|
586
|
+
for (const sdk of sdksOfFile) {
|
|
587
|
+
if (!importerSdks.has(sdk)) {
|
|
588
|
+
importerSdks.add(sdk);
|
|
589
|
+
grew = true;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
if (grew)
|
|
593
|
+
worklist.push(importer);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
return {
|
|
597
|
+
transitiveSdks,
|
|
598
|
+
stats: {
|
|
599
|
+
filesWalked: fileSet.size,
|
|
600
|
+
seedFiles: directSdks.size,
|
|
601
|
+
inScopeFiles: transitiveSdks.size,
|
|
602
|
+
edgesResolved,
|
|
603
|
+
edgesUnresolved,
|
|
604
|
+
},
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
// -- Language helper ----------------------------------------------------------
|
|
608
|
+
/**
|
|
609
|
+
* Returns true when the file path is a TS/JS source flagshark would parse.
|
|
610
|
+
* Mirrors the file-extension set used by TypeScriptDetector / JavaScriptDetector.
|
|
611
|
+
*/
|
|
612
|
+
/**
|
|
613
|
+
* True if the file is a Python source file the graph should walk.
|
|
614
|
+
* Mirrors the extension list of the Python detector — keep in sync.
|
|
615
|
+
*/
|
|
616
|
+
export function isPythonFile(filePath) {
|
|
617
|
+
const lower = filePath.toLowerCase();
|
|
618
|
+
return lower.endsWith('.py') || lower.endsWith('.pyx') || lower.endsWith('.pyi');
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Polyglot scope predicate: true for TS/JS *and* Python source files.
|
|
622
|
+
* Pass this as `ImportGraphOptions.isTsJs` when you want the graph to
|
|
623
|
+
* walk Python wrappers too. Replaces the TS/JS-only check incrementally
|
|
624
|
+
* without forcing every caller to update.
|
|
625
|
+
*/
|
|
626
|
+
export function isScannedSourceFile(filePath) {
|
|
627
|
+
return isTsJsFile(filePath) || isPythonFile(filePath);
|
|
628
|
+
}
|
|
629
|
+
export function isTsJsFile(filePath) {
|
|
630
|
+
const lower = filePath.toLowerCase();
|
|
631
|
+
const dot = lower.lastIndexOf('.');
|
|
632
|
+
if (dot === -1)
|
|
633
|
+
return false;
|
|
634
|
+
const ext = lower.slice(dot);
|
|
635
|
+
return TS_JS_EXTENSIONS.includes(ext);
|
|
636
|
+
}
|
|
637
|
+
// Exported for tests so they can assert on the resolution-order without
|
|
638
|
+
// re-listing the constant.
|
|
639
|
+
export const _TS_JS_EXTENSIONS_FOR_TESTS = TS_JS_EXTENSIONS;
|
|
640
|
+
export { Languages };
|
|
641
|
+
//# sourceMappingURL=import-graph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-graph.js","sourceRoot":"","sources":["../../src/detection/import-graph.ts"],"names":[],"mappings":"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"}
|