@c4a/extract 0.5.41-beta.4 → 0.5.41-beta.6
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/bin/c4a-extract-code.js +77 -48
- package/index.js +77 -48
- package/package.json +1 -1
package/bin/c4a-extract-code.js
CHANGED
|
@@ -13891,11 +13891,11 @@ class ExtractionPluginRegistry {
|
|
|
13891
13891
|
}
|
|
13892
13892
|
|
|
13893
13893
|
// src/scanner.ts
|
|
13894
|
-
import {
|
|
13894
|
+
import { execFile } from "node:child_process";
|
|
13895
13895
|
import { access, readdir, readFile } from "node:fs/promises";
|
|
13896
13896
|
import { basename, extname, join, relative, resolve, sep } from "node:path";
|
|
13897
13897
|
import { promisify } from "node:util";
|
|
13898
|
-
var
|
|
13898
|
+
var execFileAsync = promisify(execFile);
|
|
13899
13899
|
var isScanExcludedDir = (name) => SCAN_EXCLUDED_DIRS.has(name) || name.startsWith(".") && name !== "." || name.endsWith(".egg-info");
|
|
13900
13900
|
var DEFAULT_EXCLUDED_FILE_PATTERNS = [
|
|
13901
13901
|
/\.test\.ts$/i,
|
|
@@ -13906,9 +13906,18 @@ var SUPPORTED_EXTENSIONS = new Set([".ts", ".tsx"]);
|
|
|
13906
13906
|
var toPosixPath = (value) => value.split(sep).join("/");
|
|
13907
13907
|
var shouldExcludeFile = (fileName) => DEFAULT_EXCLUDED_FILE_PATTERNS.some((pattern) => pattern.test(fileName));
|
|
13908
13908
|
var isSupportedSourceFile = (fileName) => SUPPORTED_EXTENSIONS.has(extname(fileName));
|
|
13909
|
+
var gitScopeArgs = (prefix) => {
|
|
13910
|
+
const scope = prefix.replace(/\/+$/u, "");
|
|
13911
|
+
return scope.length > 0 ? ["--", scope] : [];
|
|
13912
|
+
};
|
|
13913
|
+
var stripGitPrefix = (filePath, prefix) => {
|
|
13914
|
+
if (!prefix)
|
|
13915
|
+
return filePath;
|
|
13916
|
+
return filePath.startsWith(prefix) ? filePath.slice(prefix.length) : null;
|
|
13917
|
+
};
|
|
13909
13918
|
var tryGitListFiles = async (rootDir, ref) => {
|
|
13910
13919
|
try {
|
|
13911
|
-
const { stdout: gitRootRaw } = await
|
|
13920
|
+
const { stdout: gitRootRaw } = await execFileAsync("git", ["rev-parse", "--show-toplevel"], {
|
|
13912
13921
|
cwd: rootDir
|
|
13913
13922
|
});
|
|
13914
13923
|
const gitRoot = gitRootRaw.trim();
|
|
@@ -13919,33 +13928,31 @@ var tryGitListFiles = async (rootDir, ref) => {
|
|
|
13919
13928
|
if (treeRef !== "HEAD" && !/^[0-9a-fA-F]{4,40}$/.test(treeRef)) {
|
|
13920
13929
|
return null;
|
|
13921
13930
|
}
|
|
13922
|
-
const
|
|
13931
|
+
const scopeArgs = gitScopeArgs(prefix);
|
|
13932
|
+
const { stdout: treeOutput } = await execFileAsync("git", ["ls-tree", "-r", "--name-only", treeRef, ...scopeArgs], { cwd: gitRoot, maxBuffer: 64 * 1024 * 1024 });
|
|
13923
13933
|
const fileSet = new Set;
|
|
13924
13934
|
for (const line of treeOutput.split(`
|
|
13925
13935
|
`)) {
|
|
13926
13936
|
const trimmed = line.trim();
|
|
13927
13937
|
if (!trimmed)
|
|
13928
13938
|
continue;
|
|
13929
|
-
|
|
13930
|
-
|
|
13931
|
-
|
|
13932
|
-
fileSet.add(trimmed.slice(prefix.length));
|
|
13933
|
-
} else {
|
|
13934
|
-
fileSet.add(trimmed);
|
|
13935
|
-
}
|
|
13939
|
+
const relPath = stripGitPrefix(trimmed, prefix);
|
|
13940
|
+
if (relPath)
|
|
13941
|
+
fileSet.add(relPath);
|
|
13936
13942
|
}
|
|
13937
13943
|
if (!ref) {
|
|
13938
|
-
const { stdout: diffOutput } = await
|
|
13944
|
+
const { stdout: diffOutput } = await execFileAsync("git", ["diff", "--name-status", "HEAD", ...scopeArgs], { cwd: gitRoot, maxBuffer: 16 * 1024 * 1024 });
|
|
13939
13945
|
for (const line of diffOutput.split(`
|
|
13940
13946
|
`)) {
|
|
13941
13947
|
const trimmed = line.trim();
|
|
13942
13948
|
if (!trimmed)
|
|
13943
13949
|
continue;
|
|
13944
|
-
const
|
|
13945
|
-
const
|
|
13950
|
+
const parts = trimmed.split("\t");
|
|
13951
|
+
const status = parts[0]?.[0];
|
|
13952
|
+
const filePath = status === "R" || status === "C" ? parts[2] : parts[1] ?? trimmed.slice(1).trim();
|
|
13946
13953
|
if (!filePath)
|
|
13947
13954
|
continue;
|
|
13948
|
-
const relPath =
|
|
13955
|
+
const relPath = stripGitPrefix(filePath, prefix);
|
|
13949
13956
|
if (!relPath)
|
|
13950
13957
|
continue;
|
|
13951
13958
|
if (status === "D") {
|
|
@@ -13954,7 +13961,7 @@ var tryGitListFiles = async (rootDir, ref) => {
|
|
|
13954
13961
|
fileSet.add(relPath);
|
|
13955
13962
|
}
|
|
13956
13963
|
}
|
|
13957
|
-
const { stdout: statusOutput } = await
|
|
13964
|
+
const { stdout: statusOutput } = await execFileAsync("git", ["status", "--porcelain", "-uall", ...scopeArgs], { cwd: gitRoot, maxBuffer: 16 * 1024 * 1024 });
|
|
13958
13965
|
for (const line of statusOutput.split(`
|
|
13959
13966
|
`)) {
|
|
13960
13967
|
if (!line.startsWith("?? "))
|
|
@@ -13962,7 +13969,7 @@ var tryGitListFiles = async (rootDir, ref) => {
|
|
|
13962
13969
|
const filePath = line.slice(3).trim();
|
|
13963
13970
|
if (!filePath || filePath.endsWith("/"))
|
|
13964
13971
|
continue;
|
|
13965
|
-
const relPath =
|
|
13972
|
+
const relPath = stripGitPrefix(filePath, prefix);
|
|
13966
13973
|
if (relPath)
|
|
13967
13974
|
fileSet.add(relPath);
|
|
13968
13975
|
}
|
|
@@ -13972,42 +13979,51 @@ var tryGitListFiles = async (rootDir, ref) => {
|
|
|
13972
13979
|
return null;
|
|
13973
13980
|
}
|
|
13974
13981
|
};
|
|
13975
|
-
|
|
13982
|
+
function filterGitSourceFiles(baseDir, gitFiles, excludeDirs, pathFilter2) {
|
|
13976
13983
|
const results = [];
|
|
13977
|
-
const baseDir = resolve(rootDir);
|
|
13978
13984
|
const codePathMatcher = pathFilter2 ? createPathMatcher(pathFilter2.code) : null;
|
|
13979
13985
|
const matchesCode = (relPath, fileName) => {
|
|
13980
13986
|
if (codePathMatcher)
|
|
13981
13987
|
return codePathMatcher(relPath);
|
|
13982
13988
|
return isSupportedSourceFile(fileName) && !shouldExcludeFile(fileName);
|
|
13983
13989
|
};
|
|
13984
|
-
const
|
|
13985
|
-
|
|
13986
|
-
|
|
13987
|
-
|
|
13988
|
-
|
|
13989
|
-
|
|
13990
|
-
|
|
13991
|
-
|
|
13992
|
-
|
|
13993
|
-
|
|
13994
|
-
|
|
13990
|
+
for (const relPath of gitFiles) {
|
|
13991
|
+
const fileName = relPath.split("/").pop() ?? "";
|
|
13992
|
+
if (!matchesCode(relPath, fileName))
|
|
13993
|
+
continue;
|
|
13994
|
+
const segments = relPath.split("/");
|
|
13995
|
+
let excluded = false;
|
|
13996
|
+
for (let i = 0;i < segments.length - 1; i++) {
|
|
13997
|
+
const seg = segments[i];
|
|
13998
|
+
if (isScanExcludedDir(seg)) {
|
|
13999
|
+
excluded = true;
|
|
14000
|
+
break;
|
|
14001
|
+
}
|
|
14002
|
+
if (excludeDirs) {
|
|
14003
|
+
const dirPath = resolve(baseDir, segments.slice(0, i + 1).join("/"));
|
|
14004
|
+
if (excludeDirs.has(dirPath)) {
|
|
13995
14005
|
excluded = true;
|
|
13996
14006
|
break;
|
|
13997
14007
|
}
|
|
13998
|
-
if (excludeDirs) {
|
|
13999
|
-
const dirPath = resolve(baseDir, segments.slice(0, i + 1).join("/"));
|
|
14000
|
-
if (excludeDirs.has(dirPath)) {
|
|
14001
|
-
excluded = true;
|
|
14002
|
-
break;
|
|
14003
|
-
}
|
|
14004
|
-
}
|
|
14005
14008
|
}
|
|
14006
|
-
if (excluded)
|
|
14007
|
-
continue;
|
|
14008
|
-
results.push(toPosixPath(relPath));
|
|
14009
14009
|
}
|
|
14010
|
-
|
|
14010
|
+
if (!excluded)
|
|
14011
|
+
results.push(toPosixPath(relPath));
|
|
14012
|
+
}
|
|
14013
|
+
return results.sort();
|
|
14014
|
+
}
|
|
14015
|
+
var scanSourceFiles = async (rootDir, excludeDirs, ref, pathFilter2) => {
|
|
14016
|
+
const results = [];
|
|
14017
|
+
const baseDir = resolve(rootDir);
|
|
14018
|
+
const codePathMatcher = pathFilter2 ? createPathMatcher(pathFilter2.code) : null;
|
|
14019
|
+
const matchesCode = (relPath, fileName) => {
|
|
14020
|
+
if (codePathMatcher)
|
|
14021
|
+
return codePathMatcher(relPath);
|
|
14022
|
+
return isSupportedSourceFile(fileName) && !shouldExcludeFile(fileName);
|
|
14023
|
+
};
|
|
14024
|
+
const gitFiles = await tryGitListFiles(baseDir, ref);
|
|
14025
|
+
if (gitFiles && gitFiles.size > 0) {
|
|
14026
|
+
return filterGitSourceFiles(baseDir, gitFiles, excludeDirs, pathFilter2);
|
|
14011
14027
|
}
|
|
14012
14028
|
const visit = async (currentDir) => {
|
|
14013
14029
|
const entries = await readdir(currentDir, { withFileTypes: true });
|
|
@@ -14160,9 +14176,9 @@ var findSubModuleDirs = async (rootDir, excludeDirs, gitFiles, pathFilter2) => {
|
|
|
14160
14176
|
await walk(root);
|
|
14161
14177
|
return results;
|
|
14162
14178
|
};
|
|
14163
|
-
var buildModule = async (repoRoot, moduleDir, moduleName, childModuleDirs, ref, pathFilter2) => {
|
|
14179
|
+
var buildModule = async (repoRoot, moduleDir, moduleName, childModuleDirs, ref, pathFilter2, gitFiles) => {
|
|
14164
14180
|
const excludes = childModuleDirs.size > 0 ? childModuleDirs : undefined;
|
|
14165
|
-
const moduleFiles = await scanSourceFiles(moduleDir, excludes, ref, pathFilter2);
|
|
14181
|
+
const moduleFiles = gitFiles !== undefined && gitFiles !== null && gitFiles.size > 0 ? filterGitSourceFiles(resolve(moduleDir), gitFiles, excludes, pathFilter2) : await scanSourceFiles(moduleDir, excludes, ref, pathFilter2);
|
|
14166
14182
|
const modulePath = toPosixPath(relative(repoRoot, moduleDir)) || ".";
|
|
14167
14183
|
const totalLines = await Promise.all(moduleFiles.map((file) => countFileLines(join(moduleDir, file))));
|
|
14168
14184
|
const files = modulePath === "." ? moduleFiles : moduleFiles.map((file) => toPosixPath(join(modulePath, file)));
|
|
@@ -14174,6 +14190,20 @@ var buildModule = async (repoRoot, moduleDir, moduleName, childModuleDirs, ref,
|
|
|
14174
14190
|
totalLines: totalLines.reduce((sum, value) => sum + value, 0)
|
|
14175
14191
|
};
|
|
14176
14192
|
};
|
|
14193
|
+
function scopedGitFiles(gitFiles, scopeRel) {
|
|
14194
|
+
if (gitFiles === null)
|
|
14195
|
+
return null;
|
|
14196
|
+
const normalizedScope = toPosixPath(scopeRel).replace(/\/+$/u, "");
|
|
14197
|
+
if (!normalizedScope || normalizedScope === ".")
|
|
14198
|
+
return gitFiles;
|
|
14199
|
+
const prefix = `${normalizedScope}/`;
|
|
14200
|
+
const scoped = new Set;
|
|
14201
|
+
for (const file of gitFiles) {
|
|
14202
|
+
if (file.startsWith(prefix))
|
|
14203
|
+
scoped.add(file.slice(prefix.length));
|
|
14204
|
+
}
|
|
14205
|
+
return scoped;
|
|
14206
|
+
}
|
|
14177
14207
|
var detectModules = async (repoPath, ref, pathFilter2) => {
|
|
14178
14208
|
const repoRoot = resolve(repoPath);
|
|
14179
14209
|
const modules = [];
|
|
@@ -14183,7 +14213,7 @@ var detectModules = async (repoPath, ref, pathFilter2) => {
|
|
|
14183
14213
|
const rootManifest = await findManifestFile(repoRoot);
|
|
14184
14214
|
if (rootManifest) {
|
|
14185
14215
|
const rootName = await readModuleName(repoRoot, rootManifest) ?? basename(repoRoot);
|
|
14186
|
-
modules.push(await buildModule(repoRoot, repoRoot, rootName, subModuleDirSet, ref, pathFilter2));
|
|
14216
|
+
modules.push(await buildModule(repoRoot, repoRoot, rootName, subModuleDirSet, ref, pathFilter2, gitFiles));
|
|
14187
14217
|
}
|
|
14188
14218
|
for (const subDir of subModuleDirs) {
|
|
14189
14219
|
const manifest = await findManifestFile(subDir);
|
|
@@ -14191,11 +14221,10 @@ var detectModules = async (repoPath, ref, pathFilter2) => {
|
|
|
14191
14221
|
continue;
|
|
14192
14222
|
const name = await readModuleName(subDir, manifest) ?? basename(subDir);
|
|
14193
14223
|
const subDirRel = toPosixPath(relative(repoRoot, subDir));
|
|
14194
|
-
const
|
|
14195
|
-
const subGitFiles = gitFiles ? new Set([...gitFiles].filter((f) => f.startsWith(subPrefix)).map((f) => f.slice(subPrefix.length))) : null;
|
|
14224
|
+
const subGitFiles = scopedGitFiles(gitFiles, subDirRel);
|
|
14196
14225
|
const nested = await findSubModuleDirs(subDir, subModuleDirSet, subGitFiles, pathFilter2);
|
|
14197
14226
|
const nestedSet = new Set(nested.map((d) => resolve(d)));
|
|
14198
|
-
modules.push(await buildModule(repoRoot, subDir, name, nestedSet, ref, pathFilter2));
|
|
14227
|
+
modules.push(await buildModule(repoRoot, subDir, name, nestedSet, ref, pathFilter2, subGitFiles));
|
|
14199
14228
|
}
|
|
14200
14229
|
return modules.sort((a, b) => a.name.localeCompare(b.name));
|
|
14201
14230
|
};
|
|
@@ -14214,7 +14243,7 @@ var detectModuleAt = async (repoPath, modulePath, ref, pathFilter2) => {
|
|
|
14214
14243
|
const gitFiles = await tryGitListFiles(moduleDir, ref);
|
|
14215
14244
|
const nested = await findSubModuleDirs(moduleDir, undefined, gitFiles, pathFilter2);
|
|
14216
14245
|
const nestedSet = new Set(nested.map((d) => resolve(d)));
|
|
14217
|
-
return buildModule(repoRoot, moduleDir, name, nestedSet, ref, pathFilter2);
|
|
14246
|
+
return buildModule(repoRoot, moduleDir, name, nestedSet, ref, pathFilter2, gitFiles);
|
|
14218
14247
|
};
|
|
14219
14248
|
|
|
14220
14249
|
// src/repository.ts
|
package/index.js
CHANGED
|
@@ -15468,11 +15468,11 @@ import { readFile as readFile2, readdir as readdir2, stat } from "node:fs/promis
|
|
|
15468
15468
|
import path2 from "node:path";
|
|
15469
15469
|
|
|
15470
15470
|
// src/scanner.ts
|
|
15471
|
-
import {
|
|
15471
|
+
import { execFile } from "node:child_process";
|
|
15472
15472
|
import { access, readdir, readFile } from "node:fs/promises";
|
|
15473
15473
|
import { basename, extname, join, relative, resolve, sep } from "node:path";
|
|
15474
15474
|
import { promisify } from "node:util";
|
|
15475
|
-
var
|
|
15475
|
+
var execFileAsync = promisify(execFile);
|
|
15476
15476
|
var isScanExcludedDir = (name) => SCAN_EXCLUDED_DIRS.has(name) || name.startsWith(".") && name !== "." || name.endsWith(".egg-info");
|
|
15477
15477
|
var DEFAULT_EXCLUDED_FILE_PATTERNS = [
|
|
15478
15478
|
/\.test\.ts$/i,
|
|
@@ -15483,9 +15483,18 @@ var SUPPORTED_EXTENSIONS = new Set([".ts", ".tsx"]);
|
|
|
15483
15483
|
var toPosixPath = (value) => value.split(sep).join("/");
|
|
15484
15484
|
var shouldExcludeFile = (fileName) => DEFAULT_EXCLUDED_FILE_PATTERNS.some((pattern) => pattern.test(fileName));
|
|
15485
15485
|
var isSupportedSourceFile = (fileName) => SUPPORTED_EXTENSIONS.has(extname(fileName));
|
|
15486
|
+
var gitScopeArgs = (prefix) => {
|
|
15487
|
+
const scope = prefix.replace(/\/+$/u, "");
|
|
15488
|
+
return scope.length > 0 ? ["--", scope] : [];
|
|
15489
|
+
};
|
|
15490
|
+
var stripGitPrefix = (filePath, prefix) => {
|
|
15491
|
+
if (!prefix)
|
|
15492
|
+
return filePath;
|
|
15493
|
+
return filePath.startsWith(prefix) ? filePath.slice(prefix.length) : null;
|
|
15494
|
+
};
|
|
15486
15495
|
var tryGitListFiles = async (rootDir, ref) => {
|
|
15487
15496
|
try {
|
|
15488
|
-
const { stdout: gitRootRaw } = await
|
|
15497
|
+
const { stdout: gitRootRaw } = await execFileAsync("git", ["rev-parse", "--show-toplevel"], {
|
|
15489
15498
|
cwd: rootDir
|
|
15490
15499
|
});
|
|
15491
15500
|
const gitRoot = gitRootRaw.trim();
|
|
@@ -15496,33 +15505,31 @@ var tryGitListFiles = async (rootDir, ref) => {
|
|
|
15496
15505
|
if (treeRef !== "HEAD" && !/^[0-9a-fA-F]{4,40}$/.test(treeRef)) {
|
|
15497
15506
|
return null;
|
|
15498
15507
|
}
|
|
15499
|
-
const
|
|
15508
|
+
const scopeArgs = gitScopeArgs(prefix);
|
|
15509
|
+
const { stdout: treeOutput } = await execFileAsync("git", ["ls-tree", "-r", "--name-only", treeRef, ...scopeArgs], { cwd: gitRoot, maxBuffer: 64 * 1024 * 1024 });
|
|
15500
15510
|
const fileSet = new Set;
|
|
15501
15511
|
for (const line of treeOutput.split(`
|
|
15502
15512
|
`)) {
|
|
15503
15513
|
const trimmed = line.trim();
|
|
15504
15514
|
if (!trimmed)
|
|
15505
15515
|
continue;
|
|
15506
|
-
|
|
15507
|
-
|
|
15508
|
-
|
|
15509
|
-
fileSet.add(trimmed.slice(prefix.length));
|
|
15510
|
-
} else {
|
|
15511
|
-
fileSet.add(trimmed);
|
|
15512
|
-
}
|
|
15516
|
+
const relPath = stripGitPrefix(trimmed, prefix);
|
|
15517
|
+
if (relPath)
|
|
15518
|
+
fileSet.add(relPath);
|
|
15513
15519
|
}
|
|
15514
15520
|
if (!ref) {
|
|
15515
|
-
const { stdout: diffOutput } = await
|
|
15521
|
+
const { stdout: diffOutput } = await execFileAsync("git", ["diff", "--name-status", "HEAD", ...scopeArgs], { cwd: gitRoot, maxBuffer: 16 * 1024 * 1024 });
|
|
15516
15522
|
for (const line of diffOutput.split(`
|
|
15517
15523
|
`)) {
|
|
15518
15524
|
const trimmed = line.trim();
|
|
15519
15525
|
if (!trimmed)
|
|
15520
15526
|
continue;
|
|
15521
|
-
const
|
|
15522
|
-
const
|
|
15527
|
+
const parts = trimmed.split("\t");
|
|
15528
|
+
const status = parts[0]?.[0];
|
|
15529
|
+
const filePath = status === "R" || status === "C" ? parts[2] : parts[1] ?? trimmed.slice(1).trim();
|
|
15523
15530
|
if (!filePath)
|
|
15524
15531
|
continue;
|
|
15525
|
-
const relPath =
|
|
15532
|
+
const relPath = stripGitPrefix(filePath, prefix);
|
|
15526
15533
|
if (!relPath)
|
|
15527
15534
|
continue;
|
|
15528
15535
|
if (status === "D") {
|
|
@@ -15531,7 +15538,7 @@ var tryGitListFiles = async (rootDir, ref) => {
|
|
|
15531
15538
|
fileSet.add(relPath);
|
|
15532
15539
|
}
|
|
15533
15540
|
}
|
|
15534
|
-
const { stdout: statusOutput } = await
|
|
15541
|
+
const { stdout: statusOutput } = await execFileAsync("git", ["status", "--porcelain", "-uall", ...scopeArgs], { cwd: gitRoot, maxBuffer: 16 * 1024 * 1024 });
|
|
15535
15542
|
for (const line of statusOutput.split(`
|
|
15536
15543
|
`)) {
|
|
15537
15544
|
if (!line.startsWith("?? "))
|
|
@@ -15539,7 +15546,7 @@ var tryGitListFiles = async (rootDir, ref) => {
|
|
|
15539
15546
|
const filePath = line.slice(3).trim();
|
|
15540
15547
|
if (!filePath || filePath.endsWith("/"))
|
|
15541
15548
|
continue;
|
|
15542
|
-
const relPath =
|
|
15549
|
+
const relPath = stripGitPrefix(filePath, prefix);
|
|
15543
15550
|
if (relPath)
|
|
15544
15551
|
fileSet.add(relPath);
|
|
15545
15552
|
}
|
|
@@ -15549,42 +15556,51 @@ var tryGitListFiles = async (rootDir, ref) => {
|
|
|
15549
15556
|
return null;
|
|
15550
15557
|
}
|
|
15551
15558
|
};
|
|
15552
|
-
|
|
15559
|
+
function filterGitSourceFiles(baseDir, gitFiles, excludeDirs, pathFilter2) {
|
|
15553
15560
|
const results = [];
|
|
15554
|
-
const baseDir = resolve(rootDir);
|
|
15555
15561
|
const codePathMatcher = pathFilter2 ? createPathMatcher(pathFilter2.code) : null;
|
|
15556
15562
|
const matchesCode = (relPath, fileName) => {
|
|
15557
15563
|
if (codePathMatcher)
|
|
15558
15564
|
return codePathMatcher(relPath);
|
|
15559
15565
|
return isSupportedSourceFile(fileName) && !shouldExcludeFile(fileName);
|
|
15560
15566
|
};
|
|
15561
|
-
const
|
|
15562
|
-
|
|
15563
|
-
|
|
15564
|
-
|
|
15565
|
-
|
|
15566
|
-
|
|
15567
|
-
|
|
15568
|
-
|
|
15569
|
-
|
|
15570
|
-
|
|
15571
|
-
|
|
15567
|
+
for (const relPath of gitFiles) {
|
|
15568
|
+
const fileName = relPath.split("/").pop() ?? "";
|
|
15569
|
+
if (!matchesCode(relPath, fileName))
|
|
15570
|
+
continue;
|
|
15571
|
+
const segments = relPath.split("/");
|
|
15572
|
+
let excluded = false;
|
|
15573
|
+
for (let i = 0;i < segments.length - 1; i++) {
|
|
15574
|
+
const seg = segments[i];
|
|
15575
|
+
if (isScanExcludedDir(seg)) {
|
|
15576
|
+
excluded = true;
|
|
15577
|
+
break;
|
|
15578
|
+
}
|
|
15579
|
+
if (excludeDirs) {
|
|
15580
|
+
const dirPath = resolve(baseDir, segments.slice(0, i + 1).join("/"));
|
|
15581
|
+
if (excludeDirs.has(dirPath)) {
|
|
15572
15582
|
excluded = true;
|
|
15573
15583
|
break;
|
|
15574
15584
|
}
|
|
15575
|
-
if (excludeDirs) {
|
|
15576
|
-
const dirPath = resolve(baseDir, segments.slice(0, i + 1).join("/"));
|
|
15577
|
-
if (excludeDirs.has(dirPath)) {
|
|
15578
|
-
excluded = true;
|
|
15579
|
-
break;
|
|
15580
|
-
}
|
|
15581
|
-
}
|
|
15582
15585
|
}
|
|
15583
|
-
if (excluded)
|
|
15584
|
-
continue;
|
|
15585
|
-
results.push(toPosixPath(relPath));
|
|
15586
15586
|
}
|
|
15587
|
-
|
|
15587
|
+
if (!excluded)
|
|
15588
|
+
results.push(toPosixPath(relPath));
|
|
15589
|
+
}
|
|
15590
|
+
return results.sort();
|
|
15591
|
+
}
|
|
15592
|
+
var scanSourceFiles = async (rootDir, excludeDirs, ref, pathFilter2) => {
|
|
15593
|
+
const results = [];
|
|
15594
|
+
const baseDir = resolve(rootDir);
|
|
15595
|
+
const codePathMatcher = pathFilter2 ? createPathMatcher(pathFilter2.code) : null;
|
|
15596
|
+
const matchesCode = (relPath, fileName) => {
|
|
15597
|
+
if (codePathMatcher)
|
|
15598
|
+
return codePathMatcher(relPath);
|
|
15599
|
+
return isSupportedSourceFile(fileName) && !shouldExcludeFile(fileName);
|
|
15600
|
+
};
|
|
15601
|
+
const gitFiles = await tryGitListFiles(baseDir, ref);
|
|
15602
|
+
if (gitFiles && gitFiles.size > 0) {
|
|
15603
|
+
return filterGitSourceFiles(baseDir, gitFiles, excludeDirs, pathFilter2);
|
|
15588
15604
|
}
|
|
15589
15605
|
const visit = async (currentDir) => {
|
|
15590
15606
|
const entries = await readdir(currentDir, { withFileTypes: true });
|
|
@@ -15737,9 +15753,9 @@ var findSubModuleDirs = async (rootDir, excludeDirs, gitFiles, pathFilter2) => {
|
|
|
15737
15753
|
await walk(root);
|
|
15738
15754
|
return results;
|
|
15739
15755
|
};
|
|
15740
|
-
var buildModule = async (repoRoot, moduleDir, moduleName, childModuleDirs, ref, pathFilter2) => {
|
|
15756
|
+
var buildModule = async (repoRoot, moduleDir, moduleName, childModuleDirs, ref, pathFilter2, gitFiles) => {
|
|
15741
15757
|
const excludes = childModuleDirs.size > 0 ? childModuleDirs : undefined;
|
|
15742
|
-
const moduleFiles = await scanSourceFiles(moduleDir, excludes, ref, pathFilter2);
|
|
15758
|
+
const moduleFiles = gitFiles !== undefined && gitFiles !== null && gitFiles.size > 0 ? filterGitSourceFiles(resolve(moduleDir), gitFiles, excludes, pathFilter2) : await scanSourceFiles(moduleDir, excludes, ref, pathFilter2);
|
|
15743
15759
|
const modulePath = toPosixPath(relative(repoRoot, moduleDir)) || ".";
|
|
15744
15760
|
const totalLines = await Promise.all(moduleFiles.map((file) => countFileLines(join(moduleDir, file))));
|
|
15745
15761
|
const files = modulePath === "." ? moduleFiles : moduleFiles.map((file) => toPosixPath(join(modulePath, file)));
|
|
@@ -15751,6 +15767,20 @@ var buildModule = async (repoRoot, moduleDir, moduleName, childModuleDirs, ref,
|
|
|
15751
15767
|
totalLines: totalLines.reduce((sum, value) => sum + value, 0)
|
|
15752
15768
|
};
|
|
15753
15769
|
};
|
|
15770
|
+
function scopedGitFiles(gitFiles, scopeRel) {
|
|
15771
|
+
if (gitFiles === null)
|
|
15772
|
+
return null;
|
|
15773
|
+
const normalizedScope = toPosixPath(scopeRel).replace(/\/+$/u, "");
|
|
15774
|
+
if (!normalizedScope || normalizedScope === ".")
|
|
15775
|
+
return gitFiles;
|
|
15776
|
+
const prefix = `${normalizedScope}/`;
|
|
15777
|
+
const scoped = new Set;
|
|
15778
|
+
for (const file of gitFiles) {
|
|
15779
|
+
if (file.startsWith(prefix))
|
|
15780
|
+
scoped.add(file.slice(prefix.length));
|
|
15781
|
+
}
|
|
15782
|
+
return scoped;
|
|
15783
|
+
}
|
|
15754
15784
|
var detectModules = async (repoPath, ref, pathFilter2) => {
|
|
15755
15785
|
const repoRoot = resolve(repoPath);
|
|
15756
15786
|
const modules = [];
|
|
@@ -15760,7 +15790,7 @@ var detectModules = async (repoPath, ref, pathFilter2) => {
|
|
|
15760
15790
|
const rootManifest = await findManifestFile(repoRoot);
|
|
15761
15791
|
if (rootManifest) {
|
|
15762
15792
|
const rootName = await readModuleName(repoRoot, rootManifest) ?? basename(repoRoot);
|
|
15763
|
-
modules.push(await buildModule(repoRoot, repoRoot, rootName, subModuleDirSet, ref, pathFilter2));
|
|
15793
|
+
modules.push(await buildModule(repoRoot, repoRoot, rootName, subModuleDirSet, ref, pathFilter2, gitFiles));
|
|
15764
15794
|
}
|
|
15765
15795
|
for (const subDir of subModuleDirs) {
|
|
15766
15796
|
const manifest = await findManifestFile(subDir);
|
|
@@ -15768,11 +15798,10 @@ var detectModules = async (repoPath, ref, pathFilter2) => {
|
|
|
15768
15798
|
continue;
|
|
15769
15799
|
const name = await readModuleName(subDir, manifest) ?? basename(subDir);
|
|
15770
15800
|
const subDirRel = toPosixPath(relative(repoRoot, subDir));
|
|
15771
|
-
const
|
|
15772
|
-
const subGitFiles = gitFiles ? new Set([...gitFiles].filter((f) => f.startsWith(subPrefix)).map((f) => f.slice(subPrefix.length))) : null;
|
|
15801
|
+
const subGitFiles = scopedGitFiles(gitFiles, subDirRel);
|
|
15773
15802
|
const nested = await findSubModuleDirs(subDir, subModuleDirSet, subGitFiles, pathFilter2);
|
|
15774
15803
|
const nestedSet = new Set(nested.map((d) => resolve(d)));
|
|
15775
|
-
modules.push(await buildModule(repoRoot, subDir, name, nestedSet, ref, pathFilter2));
|
|
15804
|
+
modules.push(await buildModule(repoRoot, subDir, name, nestedSet, ref, pathFilter2, subGitFiles));
|
|
15776
15805
|
}
|
|
15777
15806
|
return modules.sort((a, b) => a.name.localeCompare(b.name));
|
|
15778
15807
|
};
|
|
@@ -15791,7 +15820,7 @@ var detectModuleAt = async (repoPath, modulePath, ref, pathFilter2) => {
|
|
|
15791
15820
|
const gitFiles = await tryGitListFiles(moduleDir, ref);
|
|
15792
15821
|
const nested = await findSubModuleDirs(moduleDir, undefined, gitFiles, pathFilter2);
|
|
15793
15822
|
const nestedSet = new Set(nested.map((d) => resolve(d)));
|
|
15794
|
-
return buildModule(repoRoot, moduleDir, name, nestedSet, ref, pathFilter2);
|
|
15823
|
+
return buildModule(repoRoot, moduleDir, name, nestedSet, ref, pathFilter2, gitFiles);
|
|
15795
15824
|
};
|
|
15796
15825
|
|
|
15797
15826
|
// src/repository.ts
|