@archpilotlabs/archpilot 0.2.4 → 0.2.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/CHANGELOG.md +60 -0
- package/dist/archpilot-cli.js +459 -66
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,65 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.6
|
|
4
|
+
|
|
5
|
+
### Improved
|
|
6
|
+
|
|
7
|
+
- Improved Smart Init component and repository topology classification across complex monorepos and multi-module repositories.
|
|
8
|
+
- Improved component classification accuracy across TypeScript/NestJS, Java/Spring, frontend, backend, library, multi-module, and mixed repository structures.
|
|
9
|
+
- Improved API-design analysis precision for terminal or unconditional collection endpoints.
|
|
10
|
+
- Improved event-architecture analysis for Spring listener declarations and inherited event types.
|
|
11
|
+
- Improved data-query-risk handling for real-world SQL, JPQL, Spring Data repository, and query-builder patterns.
|
|
12
|
+
- Bounded data-query-risk analysis for complex Java/Spring repository declarations to avoid pathological validation time.
|
|
13
|
+
- Expanded regression coverage from validation against multiple real public repository shapes.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- Fixed runtime Nx projects and shared libraries being missed or misclassified in package-layout workspaces.
|
|
18
|
+
- Fixed Maven runtime, library, support, distribution, and deploy-skipped modules being over- or under-promoted during Smart Init.
|
|
19
|
+
- Fixed file-like candidate paths aborting Smart Init traversal.
|
|
20
|
+
- Fixed terminal throw-only collection endpoints being reported as missing pagination.
|
|
21
|
+
- Fixed Spring event listeners using annotation attributes, `ApplicationListener<T>`, or parent event types being treated as unhandled.
|
|
22
|
+
- Fixed bounded Spring Data repository queries with `Pageable` or `Limit` parameters being reported as unbounded collection reads.
|
|
23
|
+
- Fixed SQL-looking comments, non-query files, and Spring configuration files contributing noisy data-query-risk findings.
|
|
24
|
+
|
|
25
|
+
### Notes
|
|
26
|
+
|
|
27
|
+
- This release focuses on public-repository model accuracy and analyzer correctness.
|
|
28
|
+
- These changes improve model and finding accuracy without changing rule IDs, severities, score weights, scoring caps, or normalization behavior.
|
|
29
|
+
- Existing architecture configurations remain backward compatible.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 0.2.5
|
|
34
|
+
|
|
35
|
+
### Improved
|
|
36
|
+
|
|
37
|
+
- Improved Smart Init classification for mixed backend, frontend, and library monorepos.
|
|
38
|
+
- Improved NestJS detection so runtime applications with package publishing metadata are classified as backend services, while reusable NestJS packages remain libraries.
|
|
39
|
+
- Improved component discovery so test-only packages, build and lint tooling, and scaffold templates are excluded from default governed architecture boundaries.
|
|
40
|
+
- Improved backend resource detection for GraphQL APIs and PostgreSQL databases.
|
|
41
|
+
- Improved data-query-risk analysis for parameterized and interpolated query limits, PostgreSQL catalog lookups, and existence queries.
|
|
42
|
+
- Improved source-scope handling for authorization analysis and controller-role detection.
|
|
43
|
+
- Improved CLI version reporting in bundled and packed executables.
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
|
|
47
|
+
- Fixed NestJS backend applications being classified only as Node.js libraries when package entry points or publishing metadata were present.
|
|
48
|
+
- Fixed Playwright test packages, lint-rule packages, build tooling, and nested scaffold templates being proposed as governed components.
|
|
49
|
+
- Fixed authorization findings being emitted from confirmed specification and test source.
|
|
50
|
+
- Fixed bounded SQL queries using parameterized or interpolated `LIMIT` values being reported as unbounded collection reads.
|
|
51
|
+
- Fixed PostgreSQL catalog identity and existence lookups being treated as application collection queries.
|
|
52
|
+
- Fixed generic `handlers` directories being interpreted as controller layers without structural controller evidence.
|
|
53
|
+
- Fixed bundled CLI artifacts reporting a stale version because package metadata could not be resolved at runtime.
|
|
54
|
+
|
|
55
|
+
### Notes
|
|
56
|
+
|
|
57
|
+
- These changes improve model and finding accuracy without changing rule IDs, severities, score weights, scoring caps, or normalization behavior.
|
|
58
|
+
- Oversized services, direct persistence access, unbounded collection processing, repeated query patterns, and dependency-boundary violations remain reportable when supported by credible evidence.
|
|
59
|
+
- Documentation, examples, integration tests, and tooling remain governed when explicitly included by the generated or reviewed architecture configuration.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
3
63
|
## 0.2.4
|
|
4
64
|
|
|
5
65
|
### Improved
|
package/dist/archpilot-cli.js
CHANGED
|
@@ -12907,7 +12907,7 @@ ${lanes.join("\n")}
|
|
|
12907
12907
|
return process.memoryUsage().heapUsed;
|
|
12908
12908
|
},
|
|
12909
12909
|
getFileSize(path74) {
|
|
12910
|
-
const stat =
|
|
12910
|
+
const stat = statSync2(path74);
|
|
12911
12911
|
if (stat == null ? void 0 : stat.isFile()) {
|
|
12912
12912
|
return stat.size;
|
|
12913
12913
|
}
|
|
@@ -12951,7 +12951,7 @@ ${lanes.join("\n")}
|
|
|
12951
12951
|
}
|
|
12952
12952
|
};
|
|
12953
12953
|
return nodeSystem;
|
|
12954
|
-
function
|
|
12954
|
+
function statSync2(path74) {
|
|
12955
12955
|
try {
|
|
12956
12956
|
return _fs.statSync(path74, statSyncOptions);
|
|
12957
12957
|
} catch {
|
|
@@ -13010,7 +13010,7 @@ ${lanes.join("\n")}
|
|
|
13010
13010
|
activeSession.post("Profiler.stop", (err, { profile }) => {
|
|
13011
13011
|
var _a;
|
|
13012
13012
|
if (!err) {
|
|
13013
|
-
if ((_a =
|
|
13013
|
+
if ((_a = statSync2(profilePath)) == null ? void 0 : _a.isDirectory()) {
|
|
13014
13014
|
profilePath = _path.join(profilePath, `${(/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-")}+P${process.pid}.cpuprofile`);
|
|
13015
13015
|
}
|
|
13016
13016
|
try {
|
|
@@ -13130,7 +13130,7 @@ ${lanes.join("\n")}
|
|
|
13130
13130
|
let stat;
|
|
13131
13131
|
if (typeof dirent === "string" || dirent.isSymbolicLink()) {
|
|
13132
13132
|
const name = combinePaths(path74, entry);
|
|
13133
|
-
stat =
|
|
13133
|
+
stat = statSync2(name);
|
|
13134
13134
|
if (!stat) {
|
|
13135
13135
|
continue;
|
|
13136
13136
|
}
|
|
@@ -13154,7 +13154,7 @@ ${lanes.join("\n")}
|
|
|
13154
13154
|
return matchFiles(path74, extensions, excludes, includes, useCaseSensitiveFileNames2, process.cwd(), depth, getAccessibleFileSystemEntries, realpath);
|
|
13155
13155
|
}
|
|
13156
13156
|
function fileSystemEntryExists(path74, entryKind) {
|
|
13157
|
-
const stat =
|
|
13157
|
+
const stat = statSync2(path74);
|
|
13158
13158
|
if (!stat) {
|
|
13159
13159
|
return false;
|
|
13160
13160
|
}
|
|
@@ -13196,7 +13196,7 @@ ${lanes.join("\n")}
|
|
|
13196
13196
|
}
|
|
13197
13197
|
function getModifiedTime3(path74) {
|
|
13198
13198
|
var _a;
|
|
13199
|
-
return (_a =
|
|
13199
|
+
return (_a = statSync2(path74)) == null ? void 0 : _a.mtime;
|
|
13200
13200
|
}
|
|
13201
13201
|
function setModifiedTime(path74, time) {
|
|
13202
13202
|
try {
|
|
@@ -225435,6 +225435,7 @@ init_sourceScopeClassification();
|
|
|
225435
225435
|
var maxFileSizeBytes = 256 * 1024;
|
|
225436
225436
|
var supplementalRiskScanExtensions = [".json", ".yaml", ".yml", ".sql"];
|
|
225437
225437
|
var backendCodeExtensions = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".java", ".cs", ".py", ".php", ".go"];
|
|
225438
|
+
var methodBodyScanExtensions = new Set(backendCodeExtensions);
|
|
225438
225439
|
var supplementalIgnoredDirectoryNames = [".vscode-test", ".tmp"];
|
|
225439
225440
|
var batchingEvidencePattern = /\b(?:DataLoader|Promise\.all|findMany\s*\([\s\S]{0,300}\bin\b|where\s*:\s*\{[\s\S]{0,300}\bin\s*:|include\s*:|join\s*\(|leftJoin|innerJoin|JOIN\b)\b/iu;
|
|
225440
225441
|
var queryReadPattern = /\b((?:this\.)?(?:prisma\.(\w+)|([A-Za-z_$][\w$]*Repository|repository))\.(find\w*|count|aggregate|groupBy)\s*\()/giu;
|
|
@@ -225443,6 +225444,7 @@ var boundEvidencePattern = /\b(?:take|limit|page|cursor|skip|offset|PageRequest|
|
|
|
225443
225444
|
var repeatedQueryPattern = /\b((?:this\.)?(?:prisma\.(\w+)|(\w*Repository|repository))\.(find\w*|count|aggregate|groupBy)\s*\(\s*(?:\{[\s\S]{0,300}?\}|\w+)\s*\))/giu;
|
|
225444
225445
|
var tenantPredicatePattern = /\b(?:tenantId|tenant_id|organizationId|organization_id|orgId|org_id|accountId|account_id|workspaceId|workspace_id|companyId|company_id|customerId|customer_id)\b/u;
|
|
225445
225446
|
var codePaginationEvidencePattern = /\b(?:take|skip|limit|offset|page|perPage|pageSize|cursor|Pageable|PageRequest|paginate|simplePaginate|Limit|Offset|Take|Skip|TOP\s+\d+)\b/iu;
|
|
225447
|
+
var sqlQueryInvocationHintPattern = /\b(?:query|execute|executeQuery|createNativeQuery|createQuery|FromSqlRaw|FromSqlInterpolated|Query|QueryContext|QueryRow|QueryRowContext|Exec|ExecContext|Raw|text|DB::select|DB::statement|DB::raw|DB::table)\s*\(|\$queryRaw\s*\(|\$executeRaw\s*\(|@Query\s*\(/u;
|
|
225446
225448
|
function getLineStarts(file) {
|
|
225447
225449
|
if (file.lineStarts) {
|
|
225448
225450
|
return file.lineStarts;
|
|
@@ -225656,21 +225658,38 @@ function hasSelectStar(statement) {
|
|
|
225656
225658
|
return /\bselect\s+(distinct\s+)?\*/i.test(statement);
|
|
225657
225659
|
}
|
|
225658
225660
|
function hasPaginationEvidence(statement) {
|
|
225659
|
-
|
|
225661
|
+
const boundValuePattern = "(?:\\d+|\\$\\d+|\\?|:[A-Za-z_]\\w*|@[A-Za-z_]\\w*|\\$\\{[^}]{1,120}\\}|[A-Za-z_]\\w*)";
|
|
225662
|
+
const valueTerminatorPattern = "(?=\\s|,|;|\\)|$)";
|
|
225663
|
+
return new RegExp(
|
|
225664
|
+
`\\blimit\\s+${boundValuePattern}${valueTerminatorPattern}|\\boffset\\s+${boundValuePattern}${valueTerminatorPattern}|\\bfetch\\s+(first|next)\\b|\\btop\\s+${boundValuePattern}${valueTerminatorPattern}`,
|
|
225665
|
+
"i"
|
|
225666
|
+
).test(
|
|
225660
225667
|
statement
|
|
225661
225668
|
);
|
|
225662
225669
|
}
|
|
225663
225670
|
function hasEqualityPredicate(statement, columnPattern) {
|
|
225671
|
+
const whereMatch = /\bwhere\b/iu.exec(statement);
|
|
225672
|
+
if (!whereMatch) {
|
|
225673
|
+
return false;
|
|
225674
|
+
}
|
|
225675
|
+
const predicateWindow = statement.slice(whereMatch.index, whereMatch.index + 1200);
|
|
225664
225676
|
return new RegExp(
|
|
225665
|
-
`\\
|
|
225677
|
+
`\\b(?:${columnPattern})\\b\\s*=\\s*(?:[\\w$:@?]+|'[^']+'|"[^"]+"|\\d+)`,
|
|
225666
225678
|
"iu"
|
|
225667
|
-
).test(
|
|
225679
|
+
).test(predicateWindow);
|
|
225668
225680
|
}
|
|
225669
225681
|
function isCatalogIdentifierPointLookup(statement) {
|
|
225670
|
-
|
|
225682
|
+
const metadataSourcePattern = /\bfrom\s+(?:information_schema\.(?:schemata|tables|columns|key_column_usage|table_constraints)|pg_catalog\.(?:pg_class|pg_namespace|pg_attribute|pg_constraint|pg_type|pg_enum|pg_tables|pg_indexes)|pg_(?:class|namespace|attribute|constraint|type|enum|tables|indexes))\b/iu;
|
|
225683
|
+
if (!metadataSourcePattern.test(statement)) {
|
|
225684
|
+
return false;
|
|
225685
|
+
}
|
|
225686
|
+
return hasEqualityPredicate(statement, "schema_name|table_schema|table_name|column_name|constraint_name") || hasEqualityPredicate(statement, "schemaname|tablename|relname|nspname|attname|conname|typname|enumlabel|indexname");
|
|
225671
225687
|
}
|
|
225672
225688
|
function isObviousPointLookup(statement) {
|
|
225673
225689
|
const normalized = statement.toLowerCase();
|
|
225690
|
+
if (/\bselect\s+exists\s*\(/i.test(normalized)) {
|
|
225691
|
+
return true;
|
|
225692
|
+
}
|
|
225674
225693
|
if (!normalized.includes("where")) {
|
|
225675
225694
|
return false;
|
|
225676
225695
|
}
|
|
@@ -226258,6 +226277,9 @@ function detectRepeatedQueryPattern(method) {
|
|
|
226258
226277
|
}
|
|
226259
226278
|
function extractSqlQueryLiterals(content) {
|
|
226260
226279
|
const queries = [];
|
|
226280
|
+
if (!sqlQueryInvocationHintPattern.test(content)) {
|
|
226281
|
+
return queries;
|
|
226282
|
+
}
|
|
226261
226283
|
const searchableContent = maskSourceComments(content);
|
|
226262
226284
|
const patterns = [
|
|
226263
226285
|
/(?:\b(?:[\w$]+\.)?(?:query|execute|executeQuery|createNativeQuery|createQuery|FromSqlRaw|FromSqlInterpolated|Query|QueryContext|QueryRow|QueryRowContext|Exec|ExecContext|Raw|text)|\$queryRaw|\$executeRaw)\s*\([^'"`)]{0,180}?(['"`])([\s\S]{0,900}?)\1/giu,
|
|
@@ -226279,7 +226301,7 @@ function extractSqlQueryLiterals(content) {
|
|
|
226279
226301
|
return queries;
|
|
226280
226302
|
}
|
|
226281
226303
|
function maskSourceComments(content) {
|
|
226282
|
-
|
|
226304
|
+
const masked = [];
|
|
226283
226305
|
let index = 0;
|
|
226284
226306
|
let state = "code";
|
|
226285
226307
|
let escaped = false;
|
|
@@ -226288,27 +226310,27 @@ function maskSourceComments(content) {
|
|
|
226288
226310
|
const next = content[index + 1] ?? "";
|
|
226289
226311
|
if (state === "line-comment") {
|
|
226290
226312
|
if (current === "\r" || current === "\n") {
|
|
226291
|
-
masked
|
|
226313
|
+
masked.push(current);
|
|
226292
226314
|
state = "code";
|
|
226293
226315
|
} else {
|
|
226294
|
-
masked
|
|
226316
|
+
masked.push(" ");
|
|
226295
226317
|
}
|
|
226296
226318
|
index += 1;
|
|
226297
226319
|
continue;
|
|
226298
226320
|
}
|
|
226299
226321
|
if (state === "block-comment") {
|
|
226300
226322
|
if (current === "*" && next === "/") {
|
|
226301
|
-
masked
|
|
226323
|
+
masked.push(" ");
|
|
226302
226324
|
index += 2;
|
|
226303
226325
|
state = "code";
|
|
226304
226326
|
continue;
|
|
226305
226327
|
}
|
|
226306
|
-
masked
|
|
226328
|
+
masked.push(current === "\r" || current === "\n" ? current : " ");
|
|
226307
226329
|
index += 1;
|
|
226308
226330
|
continue;
|
|
226309
226331
|
}
|
|
226310
226332
|
if (state === "single" || state === "double" || state === "template") {
|
|
226311
|
-
masked
|
|
226333
|
+
masked.push(current);
|
|
226312
226334
|
if (escaped) {
|
|
226313
226335
|
escaped = false;
|
|
226314
226336
|
} else if (current === "\\") {
|
|
@@ -226320,13 +226342,13 @@ function maskSourceComments(content) {
|
|
|
226320
226342
|
continue;
|
|
226321
226343
|
}
|
|
226322
226344
|
if (current === "/" && next === "/") {
|
|
226323
|
-
masked
|
|
226345
|
+
masked.push(" ");
|
|
226324
226346
|
index += 2;
|
|
226325
226347
|
state = "line-comment";
|
|
226326
226348
|
continue;
|
|
226327
226349
|
}
|
|
226328
226350
|
if (current === "/" && next === "*") {
|
|
226329
|
-
masked
|
|
226351
|
+
masked.push(" ");
|
|
226330
226352
|
index += 2;
|
|
226331
226353
|
state = "block-comment";
|
|
226332
226354
|
continue;
|
|
@@ -226338,10 +226360,10 @@ function maskSourceComments(content) {
|
|
|
226338
226360
|
} else if (current === "`") {
|
|
226339
226361
|
state = "template";
|
|
226340
226362
|
}
|
|
226341
|
-
masked
|
|
226363
|
+
masked.push(current);
|
|
226342
226364
|
index += 1;
|
|
226343
226365
|
}
|
|
226344
|
-
return masked;
|
|
226366
|
+
return masked.join("");
|
|
226345
226367
|
}
|
|
226346
226368
|
function detectCodeSqlQueryShapeFindings(file, config) {
|
|
226347
226369
|
const findings = [];
|
|
@@ -226371,7 +226393,7 @@ function detectCodeSqlQueryShapeFindings(file, config) {
|
|
|
226371
226393
|
target: firstTable ?? "sql-query"
|
|
226372
226394
|
}));
|
|
226373
226395
|
}
|
|
226374
|
-
if (statement.queryType === "select" && !isOperationalOrBatchQueryContext(file) && !hasPaginationEvidence(statement.statement) && !isObviousPointLookup(statement.statement) && !/\bcount\s*\(/i.test(statement.statement)) {
|
|
226396
|
+
if (statement.queryType === "select" && !isOperationalOrBatchQueryContext(file) && !hasPaginationEvidence(statement.statement) && !hasSpringDataRepositoryMethodBoundEvidence(file.content, query.offset) && !isObviousPointLookup(statement.statement) && !/\bcount\s*\(/i.test(statement.statement)) {
|
|
226375
226397
|
findings.push(createCodeFinding({
|
|
226376
226398
|
id: "AP-DQR-003",
|
|
226377
226399
|
message: `Potential unbounded query risk: SELECT query${firstTable ? ` on table '${firstTable}'` : ""} has no LIMIT/OFFSET/FETCH pagination evidence.`,
|
|
@@ -226385,6 +226407,18 @@ function detectCodeSqlQueryShapeFindings(file, config) {
|
|
|
226385
226407
|
}
|
|
226386
226408
|
return findings;
|
|
226387
226409
|
}
|
|
226410
|
+
function hasSpringDataRepositoryMethodBoundEvidence(content, queryOffset) {
|
|
226411
|
+
const annotationOffset = content.lastIndexOf("@Query", queryOffset);
|
|
226412
|
+
if (annotationOffset < 0 || queryOffset - annotationOffset > 2400) {
|
|
226413
|
+
return false;
|
|
226414
|
+
}
|
|
226415
|
+
const semicolonOffset = content.indexOf(";", queryOffset);
|
|
226416
|
+
if (semicolonOffset < queryOffset || semicolonOffset - annotationOffset > 3200) {
|
|
226417
|
+
return false;
|
|
226418
|
+
}
|
|
226419
|
+
const declarationWindow = content.slice(queryOffset, semicolonOffset + 1);
|
|
226420
|
+
return /\b(?:Page|Slice|Window)\s*</u.test(declarationWindow) && /\b(?:Pageable|Limit)\s+\w+\b/u.test(declarationWindow);
|
|
226421
|
+
}
|
|
226388
226422
|
function collectOrmReadEvidence(method) {
|
|
226389
226423
|
const patterns = [
|
|
226390
226424
|
[/\b(?:this\.)?prisma\.\w+\.findMany\s*\(/giu, "prisma.findMany"],
|
|
@@ -226502,7 +226536,11 @@ function detectCodeQueryRiskFindings(files, config, astCache) {
|
|
|
226502
226536
|
if (isProductionBackend) {
|
|
226503
226537
|
findings.push(...detectCodeSqlQueryShapeFindings(file, config));
|
|
226504
226538
|
}
|
|
226505
|
-
|
|
226539
|
+
if (!methodBodyScanExtensions.has(file.extension)) {
|
|
226540
|
+
continue;
|
|
226541
|
+
}
|
|
226542
|
+
const methods = extractMethodBodies(file, astCache);
|
|
226543
|
+
for (const method of methods) {
|
|
226506
226544
|
if (!isProductionBackend) {
|
|
226507
226545
|
continue;
|
|
226508
226546
|
}
|
|
@@ -227467,6 +227505,7 @@ var import_node_fs26 = require("node:fs");
|
|
|
227467
227505
|
var ts4 = __toESM(require_typescript());
|
|
227468
227506
|
init_moduleDiscovery();
|
|
227469
227507
|
init_archpilotIgnore();
|
|
227508
|
+
init_sourceScopeClassification();
|
|
227470
227509
|
var RuleIds = {
|
|
227471
227510
|
AUTH_MISSING_ENFORCEMENT: "AP-AUTH-001",
|
|
227472
227511
|
AUTH_INCONSISTENT_ENFORCEMENT: "AP-AUTH-002",
|
|
@@ -227897,7 +227936,10 @@ function isProtectedLooking(endpoint) {
|
|
|
227897
227936
|
}
|
|
227898
227937
|
function detectAuthorizationFindings(files, contract, astCache) {
|
|
227899
227938
|
const findings = [];
|
|
227900
|
-
|
|
227939
|
+
const productionFiles = files.filter(
|
|
227940
|
+
(file) => isProductionBackendGovernanceScope(classifyValidationSourceScope(file.relativePath))
|
|
227941
|
+
);
|
|
227942
|
+
for (const file of productionFiles) {
|
|
227901
227943
|
const moduleName = inferModuleForPath3(contract, file.relativePath);
|
|
227902
227944
|
const endpoints = extractEndpoints(file, moduleName);
|
|
227903
227945
|
if (endpoints.length === 0 && !isControllerFile(file, astCache)) {
|
|
@@ -227932,7 +227974,7 @@ function detectAuthorizationFindings(files, contract, astCache) {
|
|
|
227932
227974
|
}
|
|
227933
227975
|
}
|
|
227934
227976
|
}
|
|
227935
|
-
for (const file of
|
|
227977
|
+
for (const file of productionFiles.filter((candidate) => isRepositoryFile(candidate, astCache))) {
|
|
227936
227978
|
const roleMatch = executableAuthorizationDecisionPattern.exec(file.content);
|
|
227937
227979
|
if (!roleMatch) {
|
|
227938
227980
|
continue;
|
|
@@ -228415,7 +228457,7 @@ function classifySourceFile2(file, contract, astCache) {
|
|
|
228415
228457
|
const scope = classifyValidationSourceScope(file.relativePath);
|
|
228416
228458
|
const roles = new Set(getDeclaredRoles2(file, astCache));
|
|
228417
228459
|
const lowerPath = file.relativePath.toLowerCase();
|
|
228418
|
-
if (/(^|[./_-])controller\.(ts|tsx|js|jsx|mjs|cjs|java|cs|py|php|go)$/u.test(lowerPath) || /(^|\/)(controllers?|routers?|routes
|
|
228460
|
+
if (/(^|[./_-])controller\.(ts|tsx|js|jsx|mjs|cjs|java|cs|py|php|go)$/u.test(lowerPath) || /(^|\/)(controllers?|routers?|routes?)\//u.test(lowerPath)) {
|
|
228419
228461
|
roles.add("controller");
|
|
228420
228462
|
}
|
|
228421
228463
|
if (/(^|[./_-])service\.(ts|tsx|js|jsx|mjs|cjs|java|cs|py|php|go)$/u.test(lowerPath) || /(^|\/)(services?)\//u.test(lowerPath)) {
|
|
@@ -229954,8 +229996,15 @@ function isStaticCollectionBackedEndpoint(endpoint) {
|
|
|
229954
229996
|
}
|
|
229955
229997
|
return isStaticCollectionExpression(stripStaticLiteralNoise(expression));
|
|
229956
229998
|
}
|
|
229999
|
+
function isUnconditionallyTerminalThrowEndpoint(endpoint) {
|
|
230000
|
+
const body = endpoint.body.trim().replace(/^\{\s*/u, "").replace(/\s*\}$/u, "").trim();
|
|
230001
|
+
if (!/^throw\s+new\s+[A-Z]\w*(?:Exception|Error)\s*\([^;{}]*\)\s*;?$/u.test(body)) {
|
|
230002
|
+
return false;
|
|
230003
|
+
}
|
|
230004
|
+
return !/\b(?:if|for|while|switch|try|catch|return|await|yield)\b/u.test(body);
|
|
230005
|
+
}
|
|
229957
230006
|
function detectPaginationFindings(endpoints, contractEndpoints) {
|
|
229958
|
-
return endpoints.filter((endpoint) => isCollectionGet(endpoint) && !hasPaginationEvidence2(endpoint, contractEndpoints) && !isStaticCollectionBackedEndpoint(endpoint)).map((endpoint) => createFinding4({
|
|
230007
|
+
return endpoints.filter((endpoint) => isCollectionGet(endpoint) && !hasPaginationEvidence2(endpoint, contractEndpoints) && !isStaticCollectionBackedEndpoint(endpoint) && !isUnconditionallyTerminalThrowEndpoint(endpoint)).map((endpoint) => createFinding4({
|
|
229959
230008
|
id: RuleIds3.MISSING_PAGINATION,
|
|
229960
230009
|
message: `Collection endpoint ${endpoint.httpMethod.toUpperCase()} ${endpoint.path} lacks visible pagination evidence.`,
|
|
229961
230010
|
endpoint
|
|
@@ -230715,12 +230764,14 @@ function extractTypeScriptSignals(file, astCache) {
|
|
|
230715
230764
|
ts6.forEachChild(node, visit);
|
|
230716
230765
|
};
|
|
230717
230766
|
visit(sourceFile);
|
|
230718
|
-
return { publishes, handlers: handlers2, publicEventNames: /* @__PURE__ */ new Set() };
|
|
230767
|
+
return { publishes, handlers: handlers2, publicEventNames: /* @__PURE__ */ new Set(), eventTypeParents: /* @__PURE__ */ new Map() };
|
|
230719
230768
|
}
|
|
230720
230769
|
function extractJavaSignals(file) {
|
|
230721
230770
|
const publishes = [];
|
|
230722
230771
|
const handlers2 = [];
|
|
230723
|
-
for (const match of file.content.matchAll(
|
|
230772
|
+
for (const match of file.content.matchAll(
|
|
230773
|
+
/@EventListener\s*(?:\(\s*(?:(?:classes|value)\s*=\s*)?(?:\{\s*)?([A-Za-z_]\w*)\.class\s*(?:\})?\s*\))?/gu
|
|
230774
|
+
)) {
|
|
230724
230775
|
const eventName = match[1] ?? "ApplicationEvent";
|
|
230725
230776
|
handlers2.push({
|
|
230726
230777
|
eventName,
|
|
@@ -230732,6 +230783,21 @@ function extractJavaSignals(file) {
|
|
|
230732
230783
|
publishes: []
|
|
230733
230784
|
});
|
|
230734
230785
|
}
|
|
230786
|
+
for (const match of file.content.matchAll(/\b(?:class|interface)\s+\w+[^{;]*\bApplicationListener\s*<\s*([A-Za-z_]\w*)\s*>/gu)) {
|
|
230787
|
+
const eventName = match[1];
|
|
230788
|
+
if (!eventName) {
|
|
230789
|
+
continue;
|
|
230790
|
+
}
|
|
230791
|
+
handlers2.push({
|
|
230792
|
+
eventName,
|
|
230793
|
+
normalizedName: normalizeEventName(eventName),
|
|
230794
|
+
file,
|
|
230795
|
+
line: lineNumberForOffset5(file, match.index ?? 0),
|
|
230796
|
+
module: file.module,
|
|
230797
|
+
style: classifyEventStyle(eventName),
|
|
230798
|
+
publishes: []
|
|
230799
|
+
});
|
|
230800
|
+
}
|
|
230735
230801
|
for (const match of file.content.matchAll(/(?:await\s+)?(?:\w+\.)?(?:publishEvent|publish|emit)\s*\(\s*(?:(new)\s+([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\s*\(|(["'])([A-Za-z][\w.]*Event?|[a-z][\w.]+)\3|([A-Z][A-Za-z0-9_]*Event)\b)/gu)) {
|
|
230736
230802
|
const constructedType = match[2]?.split(".").at(-1);
|
|
230737
230803
|
const eventName = constructedType ?? match[4] ?? match[5];
|
|
@@ -230749,7 +230815,23 @@ function extractJavaSignals(file) {
|
|
|
230749
230815
|
assignedOrReturned: false
|
|
230750
230816
|
});
|
|
230751
230817
|
}
|
|
230752
|
-
return { publishes, handlers: handlers2, publicEventNames: /* @__PURE__ */ new Set() };
|
|
230818
|
+
return { publishes, handlers: handlers2, publicEventNames: /* @__PURE__ */ new Set(), eventTypeParents: extractJavaEventTypeParents(file) };
|
|
230819
|
+
}
|
|
230820
|
+
function extractJavaEventTypeParents(file) {
|
|
230821
|
+
const parentsByType = /* @__PURE__ */ new Map();
|
|
230822
|
+
for (const match of file.content.matchAll(/\b(?:class|record)\s+([A-Za-z_]\w*)(?:\s*<[^>{}]+>)?\s+extends\s+([A-Za-z_]\w*)/gu)) {
|
|
230823
|
+
const child = match[1];
|
|
230824
|
+
const parent = match[2];
|
|
230825
|
+
if (!child || !parent || !child.endsWith("Event")) {
|
|
230826
|
+
continue;
|
|
230827
|
+
}
|
|
230828
|
+
const normalizedChild = normalizeEventName(child);
|
|
230829
|
+
const normalizedParent = normalizeEventName(parent);
|
|
230830
|
+
const parents = parentsByType.get(normalizedChild) ?? /* @__PURE__ */ new Set();
|
|
230831
|
+
parents.add(normalizedParent);
|
|
230832
|
+
parentsByType.set(normalizedChild, parents);
|
|
230833
|
+
}
|
|
230834
|
+
return parentsByType;
|
|
230753
230835
|
}
|
|
230754
230836
|
function extractPublishSignalsFromText(file, body, baseOffset, pattern) {
|
|
230755
230837
|
const publishes = [];
|
|
@@ -230795,7 +230877,7 @@ function extractCsharpSignals(file) {
|
|
|
230795
230877
|
publishes: extractPublishSignalsFromText(file, classBody, classOpenBrace >= 0 ? classOpenBrace : classStart, csharpPublishPattern)
|
|
230796
230878
|
});
|
|
230797
230879
|
}
|
|
230798
|
-
return { publishes, handlers: handlers2, publicEventNames: /* @__PURE__ */ new Set() };
|
|
230880
|
+
return { publishes, handlers: handlers2, publicEventNames: /* @__PURE__ */ new Set(), eventTypeParents: /* @__PURE__ */ new Map() };
|
|
230799
230881
|
}
|
|
230800
230882
|
function extractPythonSignals(file) {
|
|
230801
230883
|
const publishes = extractPublishSignalsFromText(file, file.content, 0, pythonPublishPattern);
|
|
@@ -230818,7 +230900,7 @@ function extractPythonSignals(file) {
|
|
|
230818
230900
|
publishes: extractPublishSignalsFromText(file, block, blockStart, pythonPublishPattern)
|
|
230819
230901
|
});
|
|
230820
230902
|
}
|
|
230821
|
-
return { publishes, handlers: handlers2, publicEventNames: /* @__PURE__ */ new Set() };
|
|
230903
|
+
return { publishes, handlers: handlers2, publicEventNames: /* @__PURE__ */ new Set(), eventTypeParents: /* @__PURE__ */ new Map() };
|
|
230822
230904
|
}
|
|
230823
230905
|
function extractPhpSignals(file) {
|
|
230824
230906
|
const publishes = extractPublishSignalsFromText(file, file.content, 0, phpEventPublishPattern);
|
|
@@ -230843,7 +230925,7 @@ function extractPhpSignals(file) {
|
|
|
230843
230925
|
publishes: extractPublishSignalsFromText(file, classBody, classOpenBrace >= 0 ? classOpenBrace : classStart, phpEventPublishPattern)
|
|
230844
230926
|
});
|
|
230845
230927
|
}
|
|
230846
|
-
return { publishes, handlers: handlers2, publicEventNames: /* @__PURE__ */ new Set() };
|
|
230928
|
+
return { publishes, handlers: handlers2, publicEventNames: /* @__PURE__ */ new Set(), eventTypeParents: /* @__PURE__ */ new Map() };
|
|
230847
230929
|
}
|
|
230848
230930
|
function extractGoSignals(file) {
|
|
230849
230931
|
const publishes = extractPublishSignalsFromText(file, file.content, 0, goPublishPattern);
|
|
@@ -230863,7 +230945,7 @@ function extractGoSignals(file) {
|
|
|
230863
230945
|
publishes: []
|
|
230864
230946
|
});
|
|
230865
230947
|
}
|
|
230866
|
-
return { publishes, handlers: handlers2, publicEventNames: /* @__PURE__ */ new Set() };
|
|
230948
|
+
return { publishes, handlers: handlers2, publicEventNames: /* @__PURE__ */ new Set(), eventTypeParents: /* @__PURE__ */ new Map() };
|
|
230867
230949
|
}
|
|
230868
230950
|
function isTypeScriptLikeExtension(extension) {
|
|
230869
230951
|
return [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"].includes(extension);
|
|
@@ -230963,6 +231045,7 @@ function collectPublicTypeScriptEventNames(files, contract, astCache) {
|
|
|
230963
231045
|
function collectSignals(files, contract, astCache) {
|
|
230964
231046
|
const publishes = [];
|
|
230965
231047
|
const handlers2 = [];
|
|
231048
|
+
const eventTypeParents = /* @__PURE__ */ new Map();
|
|
230966
231049
|
const publicEventNames = collectPublicTypeScriptEventNames(files, contract, astCache);
|
|
230967
231050
|
for (const file of files) {
|
|
230968
231051
|
let signals;
|
|
@@ -230988,14 +231071,41 @@ function collectSignals(files, contract, astCache) {
|
|
|
230988
231071
|
}
|
|
230989
231072
|
publishes.push(...signals.publishes);
|
|
230990
231073
|
handlers2.push(...signals.handlers);
|
|
231074
|
+
for (const [eventName, parents] of signals.eventTypeParents) {
|
|
231075
|
+
const existing = eventTypeParents.get(eventName) ?? /* @__PURE__ */ new Set();
|
|
231076
|
+
for (const parent of parents) {
|
|
231077
|
+
existing.add(parent);
|
|
231078
|
+
}
|
|
231079
|
+
eventTypeParents.set(eventName, existing);
|
|
231080
|
+
}
|
|
231081
|
+
}
|
|
231082
|
+
return { publishes, handlers: handlers2, publicEventNames, eventTypeParents };
|
|
231083
|
+
}
|
|
231084
|
+
function isHandledEventName(normalizedName, handledNames, eventTypeParents) {
|
|
231085
|
+
const queue = [normalizedName];
|
|
231086
|
+
const visited = /* @__PURE__ */ new Set();
|
|
231087
|
+
while (queue.length > 0) {
|
|
231088
|
+
const current = queue.shift();
|
|
231089
|
+
if (!current || visited.has(current)) {
|
|
231090
|
+
continue;
|
|
231091
|
+
}
|
|
231092
|
+
if (handledNames.has(current)) {
|
|
231093
|
+
return true;
|
|
231094
|
+
}
|
|
231095
|
+
visited.add(current);
|
|
231096
|
+
for (const parent of eventTypeParents.get(current) ?? []) {
|
|
231097
|
+
if (!visited.has(parent)) {
|
|
231098
|
+
queue.push(parent);
|
|
231099
|
+
}
|
|
231100
|
+
}
|
|
230991
231101
|
}
|
|
230992
|
-
return
|
|
231102
|
+
return false;
|
|
230993
231103
|
}
|
|
230994
231104
|
function buildEventFindings(signals) {
|
|
230995
231105
|
const findings = [];
|
|
230996
231106
|
const handledNames = new Set(signals.handlers.map((handler) => handler.normalizedName));
|
|
230997
231107
|
for (const publish of signals.publishes) {
|
|
230998
|
-
if (!
|
|
231108
|
+
if (!isHandledEventName(publish.normalizedName, handledNames, signals.eventTypeParents)) {
|
|
230999
231109
|
if (signals.publicEventNames.has(publish.normalizedName)) {
|
|
231000
231110
|
continue;
|
|
231001
231111
|
}
|
|
@@ -242997,8 +243107,6 @@ var ignoredRootPathPrefixes = [
|
|
|
242997
243107
|
"static",
|
|
242998
243108
|
"assets",
|
|
242999
243109
|
"vendor",
|
|
243000
|
-
"plugins",
|
|
243001
|
-
"plugin",
|
|
243002
243110
|
"themes",
|
|
243003
243111
|
"theme",
|
|
243004
243112
|
"generated",
|
|
@@ -243021,8 +243129,12 @@ function pushEvidence(evidence, message) {
|
|
|
243021
243129
|
function safeReadDirectoryEntries(directoryPath) {
|
|
243022
243130
|
try {
|
|
243023
243131
|
return fs52.readdirSync(directoryPath, { withFileTypes: true });
|
|
243024
|
-
} catch {
|
|
243025
|
-
|
|
243132
|
+
} catch (error) {
|
|
243133
|
+
const code = typeof error === "object" && error !== null && "code" in error ? String(error.code) : "";
|
|
243134
|
+
if (code === "ENOENT" || code === "ENOTDIR") {
|
|
243135
|
+
return [];
|
|
243136
|
+
}
|
|
243137
|
+
throw error;
|
|
243026
243138
|
}
|
|
243027
243139
|
}
|
|
243028
243140
|
function safeReadJsonFile(jsonPath) {
|
|
@@ -245596,8 +245708,6 @@ function isIgnoredComponentCandidatePath(componentPath) {
|
|
|
245596
245708
|
"static",
|
|
245597
245709
|
"assets",
|
|
245598
245710
|
"vendor",
|
|
245599
|
-
"plugins",
|
|
245600
|
-
"plugin",
|
|
245601
245711
|
"themes",
|
|
245602
245712
|
"theme",
|
|
245603
245713
|
"generated",
|
|
@@ -245618,6 +245728,36 @@ function pathExists19(pathValue) {
|
|
|
245618
245728
|
return false;
|
|
245619
245729
|
}
|
|
245620
245730
|
}
|
|
245731
|
+
function isSafeMissingPathError(error) {
|
|
245732
|
+
const code = typeof error === "object" && error !== null && "code" in error ? String(error.code) : "";
|
|
245733
|
+
return code === "ENOENT" || code === "ENOTDIR";
|
|
245734
|
+
}
|
|
245735
|
+
function isDirectoryPath(pathValue) {
|
|
245736
|
+
try {
|
|
245737
|
+
return fs58.statSync(pathValue).isDirectory();
|
|
245738
|
+
} catch (error) {
|
|
245739
|
+
if (isSafeMissingPathError(error)) {
|
|
245740
|
+
return false;
|
|
245741
|
+
}
|
|
245742
|
+
throw error;
|
|
245743
|
+
}
|
|
245744
|
+
}
|
|
245745
|
+
function readDirectoryEntriesForTraversal(directoryPath, options) {
|
|
245746
|
+
if (!isDirectoryPath(directoryPath)) {
|
|
245747
|
+
return [];
|
|
245748
|
+
}
|
|
245749
|
+
try {
|
|
245750
|
+
return fs58.readdirSync(directoryPath, {
|
|
245751
|
+
withFileTypes: true,
|
|
245752
|
+
...options?.recursive ? { recursive: true } : {}
|
|
245753
|
+
});
|
|
245754
|
+
} catch (error) {
|
|
245755
|
+
if (isSafeMissingPathError(error)) {
|
|
245756
|
+
return [];
|
|
245757
|
+
}
|
|
245758
|
+
throw error;
|
|
245759
|
+
}
|
|
245760
|
+
}
|
|
245621
245761
|
function hasManifest2(workspaceRoot, componentPath) {
|
|
245622
245762
|
const absoluteRoot = componentPath === "." ? workspaceRoot : path64.join(workspaceRoot, ...componentPath.split("/"));
|
|
245623
245763
|
return [
|
|
@@ -245625,7 +245765,8 @@ function hasManifest2(workspaceRoot, componentPath) {
|
|
|
245625
245765
|
"pom.xml",
|
|
245626
245766
|
"requirements.txt",
|
|
245627
245767
|
"go.mod",
|
|
245628
|
-
"composer.json"
|
|
245768
|
+
"composer.json",
|
|
245769
|
+
"project.json"
|
|
245629
245770
|
].some((fileName) => pathExists19(path64.join(absoluteRoot, fileName)));
|
|
245630
245771
|
}
|
|
245631
245772
|
function safeReadJson(filePath) {
|
|
@@ -245648,9 +245789,21 @@ function recordKeys(value) {
|
|
|
245648
245789
|
function hasObject(value) {
|
|
245649
245790
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
245650
245791
|
}
|
|
245792
|
+
function readStringProperty(value, key) {
|
|
245793
|
+
const field = value?.[key];
|
|
245794
|
+
return typeof field === "string" && field.trim().length > 0 ? field.trim() : void 0;
|
|
245795
|
+
}
|
|
245651
245796
|
function hasPackagePublishSurface(packageJson) {
|
|
245652
245797
|
return hasObject(packageJson?.exports) || typeof packageJson?.main === "string" || typeof packageJson?.module === "string" || typeof packageJson?.types === "string" || hasObject(packageJson?.publishConfig) || Array.isArray(packageJson?.files);
|
|
245653
245798
|
}
|
|
245799
|
+
function packageDependencyNames(packageJson) {
|
|
245800
|
+
return [
|
|
245801
|
+
...recordKeys(packageJson?.dependencies),
|
|
245802
|
+
...recordKeys(packageJson?.devDependencies),
|
|
245803
|
+
...recordKeys(packageJson?.peerDependencies),
|
|
245804
|
+
...recordKeys(packageJson?.optionalDependencies)
|
|
245805
|
+
];
|
|
245806
|
+
}
|
|
245654
245807
|
function absoluteComponentRoot(workspaceRoot, componentPath) {
|
|
245655
245808
|
return componentPath === "." ? workspaceRoot : path64.join(workspaceRoot, ...componentPath.split("/"));
|
|
245656
245809
|
}
|
|
@@ -245658,6 +245811,136 @@ function readPackageJson(workspaceRoot, componentPath) {
|
|
|
245658
245811
|
const absoluteRoot = absoluteComponentRoot(workspaceRoot, componentPath);
|
|
245659
245812
|
return safeReadJson(path64.join(absoluteRoot, "package.json"));
|
|
245660
245813
|
}
|
|
245814
|
+
function readProjectJson(workspaceRoot, componentPath) {
|
|
245815
|
+
const absoluteRoot = absoluteComponentRoot(workspaceRoot, componentPath);
|
|
245816
|
+
return safeReadJson(path64.join(absoluteRoot, "project.json"));
|
|
245817
|
+
}
|
|
245818
|
+
function readNxWorkspaceLayout(workspaceRoot) {
|
|
245819
|
+
const nxJson = safeReadJson(path64.join(workspaceRoot, "nx.json"));
|
|
245820
|
+
const workspaceLayout = nxJson?.workspaceLayout;
|
|
245821
|
+
if (!hasObject(workspaceLayout)) {
|
|
245822
|
+
return {};
|
|
245823
|
+
}
|
|
245824
|
+
const layout = workspaceLayout;
|
|
245825
|
+
return {
|
|
245826
|
+
...typeof layout.appsDir === "string" && layout.appsDir.trim().length > 0 ? { appsDir: normalizePath25(layout.appsDir.trim()) } : {},
|
|
245827
|
+
...typeof layout.libsDir === "string" && layout.libsDir.trim().length > 0 ? { libsDir: normalizePath25(layout.libsDir.trim()) } : {}
|
|
245828
|
+
};
|
|
245829
|
+
}
|
|
245830
|
+
function readTargetMap(projectJson) {
|
|
245831
|
+
const targets = projectJson?.targets ?? projectJson?.architect;
|
|
245832
|
+
return hasObject(targets) ? targets : {};
|
|
245833
|
+
}
|
|
245834
|
+
function targetExecutorText(target) {
|
|
245835
|
+
if (!hasObject(target)) {
|
|
245836
|
+
return "";
|
|
245837
|
+
}
|
|
245838
|
+
const typed = target;
|
|
245839
|
+
const executor = typeof typed.executor === "string" ? typed.executor : "";
|
|
245840
|
+
const builder = typeof typed.builder === "string" ? typed.builder : "";
|
|
245841
|
+
const options = hasObject(typed.options) ? typed.options : {};
|
|
245842
|
+
const main = typeof options.main === "string" ? options.main : "";
|
|
245843
|
+
const index = typeof options.index === "string" ? options.index : "";
|
|
245844
|
+
const outputPath = typeof options.outputPath === "string" ? options.outputPath : "";
|
|
245845
|
+
return `${executor} ${builder} ${main} ${index} ${outputPath}`.toLowerCase();
|
|
245846
|
+
}
|
|
245847
|
+
function hasNxRuntimeProjectEvidence(projectJson) {
|
|
245848
|
+
const projectType = readStringProperty(projectJson, "projectType");
|
|
245849
|
+
if (projectType === "library") {
|
|
245850
|
+
return false;
|
|
245851
|
+
}
|
|
245852
|
+
const targets = readTargetMap(projectJson);
|
|
245853
|
+
const targetNames = Object.keys(targets);
|
|
245854
|
+
const targetText = targetNames.map((targetName) => `${targetName} ${targetExecutorText(targets[targetName])}`).join(" ");
|
|
245855
|
+
const hasRuntimeTarget = /\b(?:serve|start|preview|worker|package:container|deploy:static)\b/u.test(targetText);
|
|
245856
|
+
const hasBuildEntrypoint = /\bbuild\b/u.test(targetNames.join(" ")) && /(?:\bmain\b|src\/main|src\/index|public\/index|webpack|vite|next|node|container|browser|dev-server)/u.test(targetText);
|
|
245857
|
+
return projectType === "application" || hasRuntimeTarget || hasBuildEntrypoint;
|
|
245858
|
+
}
|
|
245859
|
+
function hasNxSupportOnlyProjectEvidence(projectJson) {
|
|
245860
|
+
const projectType = readStringProperty(projectJson, "projectType");
|
|
245861
|
+
const targets = readTargetMap(projectJson);
|
|
245862
|
+
const targetNames = Object.keys(targets);
|
|
245863
|
+
if (targetNames.length === 0) {
|
|
245864
|
+
return false;
|
|
245865
|
+
}
|
|
245866
|
+
const targetText = targetNames.map((targetName) => `${targetName} ${targetExecutorText(targets[targetName])}`).join(" ");
|
|
245867
|
+
const hasOnlySupportTargets = targetNames.every(
|
|
245868
|
+
(targetName) => /^(?:e2e|test|unit-test|integration-test|lint|typecheck|format|smoke|bench|benchmark)$/u.test(targetName)
|
|
245869
|
+
);
|
|
245870
|
+
const hasTestExecutor = /(?:cypress|playwright|jest|vitest|mocha|karma|protractor)/u.test(targetText);
|
|
245871
|
+
return projectType !== "library" && (hasOnlySupportTargets || hasTestExecutor);
|
|
245872
|
+
}
|
|
245873
|
+
function classifyNxRuntimeKind(projectJson) {
|
|
245874
|
+
if (!hasNxRuntimeProjectEvidence(projectJson)) {
|
|
245875
|
+
return void 0;
|
|
245876
|
+
}
|
|
245877
|
+
const targets = readTargetMap(projectJson);
|
|
245878
|
+
const targetText = Object.entries(targets).map(([targetName, target]) => `${targetName} ${targetExecutorText(target)}`).join(" ");
|
|
245879
|
+
if (/(?:webpack:dev-server|webpack-dev-server|src\/index\.(?:tsx|jsx|ts|js)|public\/index\.html|browser|react|vite|next|angular|deploy:static)/u.test(targetText)) {
|
|
245880
|
+
return "frontend";
|
|
245881
|
+
}
|
|
245882
|
+
if (/(?:@nx\/js:node|@nrwl\/node|src\/main\.(?:ts|js)|target:\s*node|node\b|container|worker|queue)/u.test(targetText)) {
|
|
245883
|
+
return /\bworker\b/u.test(targetText) ? "worker" : "backend";
|
|
245884
|
+
}
|
|
245885
|
+
return void 0;
|
|
245886
|
+
}
|
|
245887
|
+
function collectNxProjectCandidates(workspaceRoot) {
|
|
245888
|
+
if (!pathExists19(path64.join(workspaceRoot, "nx.json"))) {
|
|
245889
|
+
return [];
|
|
245890
|
+
}
|
|
245891
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
245892
|
+
const workspaceLayout = readNxWorkspaceLayout(workspaceRoot);
|
|
245893
|
+
const preferredRoots = new Set(
|
|
245894
|
+
["apps", "packages", "services", "libs", workspaceLayout.appsDir, workspaceLayout.libsDir].filter((entry) => typeof entry === "string" && entry.length > 0).map(normalizePath25)
|
|
245895
|
+
);
|
|
245896
|
+
const maxDepth = 5;
|
|
245897
|
+
const queue = [
|
|
245898
|
+
{ absolutePath: workspaceRoot, relativePath: "", depth: 0 }
|
|
245899
|
+
];
|
|
245900
|
+
const addCandidate = (candidatePath, evidence) => {
|
|
245901
|
+
const normalized = normalizePath25(candidatePath);
|
|
245902
|
+
const existing = candidates.get(normalized) ?? { path: normalized, evidence: [] };
|
|
245903
|
+
addEvidence6(existing.evidence, evidence);
|
|
245904
|
+
candidates.set(normalized, existing);
|
|
245905
|
+
};
|
|
245906
|
+
while (queue.length > 0) {
|
|
245907
|
+
const current = queue.shift();
|
|
245908
|
+
if (!current) {
|
|
245909
|
+
continue;
|
|
245910
|
+
}
|
|
245911
|
+
for (const entry of readDirectoryEntriesForTraversal(current.absolutePath)) {
|
|
245912
|
+
if (!entry.isDirectory()) {
|
|
245913
|
+
continue;
|
|
245914
|
+
}
|
|
245915
|
+
if ([".git", ".archpilot", "node_modules", "dist", "build", "out", "coverage"].includes(entry.name)) {
|
|
245916
|
+
continue;
|
|
245917
|
+
}
|
|
245918
|
+
const relativePath = normalizePath25(current.relativePath ? `${current.relativePath}/${entry.name}` : entry.name);
|
|
245919
|
+
if (current.depth >= maxDepth) {
|
|
245920
|
+
continue;
|
|
245921
|
+
}
|
|
245922
|
+
const projectJsonPath = path64.join(current.absolutePath, entry.name, "project.json");
|
|
245923
|
+
if (pathExists19(projectJsonPath)) {
|
|
245924
|
+
const projectJson = safeReadJson(projectJsonPath);
|
|
245925
|
+
const projectRoot = normalizePath25(readStringProperty(projectJson, "root") ?? relativePath);
|
|
245926
|
+
if (hasNxRuntimeProjectEvidence(projectJson)) {
|
|
245927
|
+
addCandidate(projectRoot, "Detected Nx runtime project metadata");
|
|
245928
|
+
} else if (readStringProperty(projectJson, "sourceRoot")) {
|
|
245929
|
+
addCandidate(projectRoot, "Detected Nx source-bearing project metadata");
|
|
245930
|
+
}
|
|
245931
|
+
}
|
|
245932
|
+
const firstSegment = relativePath.split("/")[0] ?? "";
|
|
245933
|
+
if (current.depth === 0 || preferredRoots.has(firstSegment) || preferredRoots.has(relativePath.split("/").slice(0, 2).join("/"))) {
|
|
245934
|
+
queue.push({
|
|
245935
|
+
absolutePath: path64.join(current.absolutePath, entry.name),
|
|
245936
|
+
relativePath,
|
|
245937
|
+
depth: current.depth + 1
|
|
245938
|
+
});
|
|
245939
|
+
}
|
|
245940
|
+
}
|
|
245941
|
+
}
|
|
245942
|
+
return [...candidates.values()].sort((left, right) => left.path.localeCompare(right.path));
|
|
245943
|
+
}
|
|
245661
245944
|
function readTextFileSafe(filePath) {
|
|
245662
245945
|
try {
|
|
245663
245946
|
return fs58.readFileSync(filePath, { encoding: "utf8" });
|
|
@@ -245704,6 +245987,8 @@ function readMavenMetadata(workspaceRoot, componentPath) {
|
|
|
245704
245987
|
testScopedDependencyCount: dependencyBlocks.filter((block) => /<scope>\s*test\s*<\/scope>/iu.test(block)).length,
|
|
245705
245988
|
totalDependencyCount: dependencyBlocks.length,
|
|
245706
245989
|
hasMavenPluginConfiguration: packaging === "maven-plugin" || /maven-plugin-plugin|<goalPrefix>|<mojo/iu.test(normalizedPom),
|
|
245990
|
+
hasAssemblyPackagingConfiguration: /maven-assembly-plugin|<goal>\s*single\s*<\/goal>|<descriptor>[^<]*(?:assembly|dist|distribution)[^<]*<\/descriptor>/iu.test(normalizedPom),
|
|
245991
|
+
hasDeploySkipConfiguration: /<maven\.deploy\.skip>\s*true\s*<\/maven\.deploy\.skip>|<artifactId>\s*maven-deploy-plugin\s*<\/artifactId>[\s\S]*?<skip>\s*true\s*<\/skip>/iu.test(normalizedPom),
|
|
245707
245992
|
hasTestLifecycleConfiguration: /maven-surefire-plugin|maven-failsafe-plugin|integration-test|failsafe|surefire/iu.test(normalizedPom),
|
|
245708
245993
|
hasArquillianEvidence: /arquillian/iu.test(normalizedPom),
|
|
245709
245994
|
hasMainJava: pathExists19(path64.join(absoluteRoot, "src", "main", "java")),
|
|
@@ -245836,6 +246121,12 @@ function buildRootCandidates(input2) {
|
|
|
245836
246121
|
addCandidate(root, `Detected project root ${root}`);
|
|
245837
246122
|
}
|
|
245838
246123
|
if (input2.workspaceRoot) {
|
|
246124
|
+
for (const candidate of collectNxProjectCandidates(input2.workspaceRoot)) {
|
|
246125
|
+
addCandidate(candidate.path, "Detected Nx project metadata");
|
|
246126
|
+
for (const evidence of candidate.evidence) {
|
|
246127
|
+
addCandidate(candidate.path, evidence);
|
|
246128
|
+
}
|
|
246129
|
+
}
|
|
245839
246130
|
const mavenRoots = [".", ...input2.topology.detectedRoots ?? []];
|
|
245840
246131
|
for (const candidate of collectMavenReactorCandidates(input2.workspaceRoot, mavenRoots)) {
|
|
245841
246132
|
addCandidate(
|
|
@@ -245919,10 +246210,7 @@ function isUnderJvmResourceRoot4(componentPath) {
|
|
|
245919
246210
|
return /(^|\/)src\/main\/resources(?:\/|$)/u.test(normalizePath25(componentPath).toLowerCase());
|
|
245920
246211
|
}
|
|
245921
246212
|
function hasFileUnderRoot(root, pattern) {
|
|
245922
|
-
|
|
245923
|
-
return false;
|
|
245924
|
-
}
|
|
245925
|
-
const entries = fs58.readdirSync(root, { recursive: true, withFileTypes: true });
|
|
246213
|
+
const entries = readDirectoryEntriesForTraversal(root, { recursive: true });
|
|
245926
246214
|
return entries.some((entry) => entry.isFile() && pattern.test(entry.name));
|
|
245927
246215
|
}
|
|
245928
246216
|
var javaMainMethodPattern = /\bpublic\s+static\s+void\s+main\s*\(\s*String\s*(?:(?:\[\s*\]\s*)|\.\.\.\s*)[A-Za-z_$][\w$]*\s*(?:\[\s*\])?\s*\)/u;
|
|
@@ -246040,10 +246328,7 @@ function readMavenProductionSourceFiles(workspaceRoot, componentPath) {
|
|
|
246040
246328
|
];
|
|
246041
246329
|
const files = [];
|
|
246042
246330
|
for (const sourceRoot of mainRoots) {
|
|
246043
|
-
|
|
246044
|
-
continue;
|
|
246045
|
-
}
|
|
246046
|
-
const entries = fs58.readdirSync(sourceRoot, { recursive: true, withFileTypes: true });
|
|
246331
|
+
const entries = readDirectoryEntriesForTraversal(sourceRoot, { recursive: true });
|
|
246047
246332
|
for (const entry of entries) {
|
|
246048
246333
|
if (!entry.isFile() || !/\.(?:java|kt|scala)$/iu.test(entry.name)) {
|
|
246049
246334
|
continue;
|
|
@@ -246215,24 +246500,67 @@ function hasRuntimeSourceFiles(workspaceRoot, componentPath) {
|
|
|
246215
246500
|
path64.join(absoluteRoot, "server")
|
|
246216
246501
|
];
|
|
246217
246502
|
for (const sourceRoot of sourceRoots) {
|
|
246218
|
-
|
|
246219
|
-
continue;
|
|
246220
|
-
}
|
|
246221
|
-
const entries = fs58.readdirSync(sourceRoot, { recursive: true, withFileTypes: true });
|
|
246503
|
+
const entries = readDirectoryEntriesForTraversal(sourceRoot, { recursive: true });
|
|
246222
246504
|
if (entries.some((entry) => entry.isFile() && /\.(?:ts|tsx|js|jsx|java|cs|py|php|go)$/iu.test(entry.name))) {
|
|
246223
246505
|
return true;
|
|
246224
246506
|
}
|
|
246225
246507
|
}
|
|
246226
246508
|
return false;
|
|
246227
246509
|
}
|
|
246510
|
+
function hasFileMatchingUnderRoot(root, pattern) {
|
|
246511
|
+
const entries = readDirectoryEntriesForTraversal(root, { recursive: true });
|
|
246512
|
+
return entries.some((entry) => entry.isFile() && pattern.test(normalizePath25(path64.join(entry.parentPath, entry.name))));
|
|
246513
|
+
}
|
|
246514
|
+
function hasNestRuntimeApplicationEvidence(workspaceRoot, componentPath, packageJson = readPackageJson(workspaceRoot, componentPath)) {
|
|
246515
|
+
const absoluteRoot = absoluteComponentRoot(workspaceRoot, componentPath);
|
|
246516
|
+
const dependencies = new Set(packageDependencyNames(packageJson));
|
|
246517
|
+
const scripts = recordKeys(packageJson?.scripts);
|
|
246518
|
+
const hasNestCore = dependencies.has("@nestjs/core");
|
|
246519
|
+
if (!hasNestCore) {
|
|
246520
|
+
return false;
|
|
246521
|
+
}
|
|
246522
|
+
const hasRuntimePlatform = dependencies.has("@nestjs/platform-express") || dependencies.has("@nestjs/platform-fastify") || dependencies.has("@nestjs/microservices") || dependencies.has("@nestjs/graphql") || dependencies.has("@nestjs/apollo");
|
|
246523
|
+
const hasRunnableScript = scripts.some((script) => /^(?:start|serve|dev|worker)(?::|$)/u.test(script));
|
|
246524
|
+
const hasNestCliConfig = ["nest-cli.json", "nest.config.js", "nest.config.ts"].some(
|
|
246525
|
+
(fileName) => pathExists19(path64.join(absoluteRoot, fileName))
|
|
246526
|
+
);
|
|
246527
|
+
const hasBootstrapEntrypoint = [
|
|
246528
|
+
path64.join(absoluteRoot, "src", "main.ts"),
|
|
246529
|
+
path64.join(absoluteRoot, "src", "main.js"),
|
|
246530
|
+
path64.join(absoluteRoot, "main.ts"),
|
|
246531
|
+
path64.join(absoluteRoot, "main.js")
|
|
246532
|
+
].some((filePath) => {
|
|
246533
|
+
const contents = readTextFileSafe(filePath);
|
|
246534
|
+
return Boolean(contents && /\bNestFactory\.create(?:ApplicationContext)?\s*\(/u.test(contents));
|
|
246535
|
+
});
|
|
246536
|
+
const srcRoot = path64.join(absoluteRoot, "src");
|
|
246537
|
+
const hasRuntimeSourceShape = hasFileMatchingUnderRoot(srcRoot, /\.(?:controller|resolver|gateway|processor|module|worker|queue)\.(?:ts|js)$/iu) || hasFileMatchingUnderRoot(srcRoot, /[/\\](?:controllers?|resolvers?|queues?|workers?)[/\\][^/\\]+\.(?:ts|js)$/iu);
|
|
246538
|
+
const hasDatabaseRuntimeIntegration = [...dependencies].some(
|
|
246539
|
+
(dependency) => /^(?:typeorm|@nestjs\/typeorm|@prisma\/client|prisma|mongoose|@nestjs\/mongoose|sequelize|@mikro-orm\/core)$/u.test(dependency)
|
|
246540
|
+
);
|
|
246541
|
+
const structuralEvidenceCount = [
|
|
246542
|
+
hasRuntimePlatform,
|
|
246543
|
+
hasRunnableScript,
|
|
246544
|
+
hasNestCliConfig,
|
|
246545
|
+
hasBootstrapEntrypoint,
|
|
246546
|
+
hasRuntimeSourceShape,
|
|
246547
|
+
hasDatabaseRuntimeIntegration
|
|
246548
|
+
].filter(Boolean).length;
|
|
246549
|
+
return hasBootstrapEntrypoint || hasRuntimePlatform && structuralEvidenceCount >= 2 || hasRunnableScript && hasRuntimeSourceShape && structuralEvidenceCount >= 3;
|
|
246550
|
+
}
|
|
246228
246551
|
function resolveKind(workspaceRoot, candidate, localProjectKinds) {
|
|
246229
246552
|
const lowerPath = candidate.path.toLowerCase();
|
|
246230
246553
|
const packageJson = readPackageJson(workspaceRoot, candidate.path);
|
|
246554
|
+
const projectJson = readProjectJson(workspaceRoot, candidate.path);
|
|
246555
|
+
const nxProjectType = readStringProperty(projectJson, "projectType");
|
|
246231
246556
|
const maven = readMavenMetadata(workspaceRoot, candidate.path);
|
|
246557
|
+
const dependencies = new Set(packageDependencyNames(packageJson));
|
|
246232
246558
|
const hasRunnableFrontendEvidence = hasRunnableFrontendComponentEvidence(workspaceRoot, candidate.path);
|
|
246559
|
+
const hasNestRuntimeEvidence = hasNestRuntimeApplicationEvidence(workspaceRoot, candidate.path, packageJson);
|
|
246560
|
+
const nxRuntimeKind = classifyNxRuntimeKind(projectJson);
|
|
246233
246561
|
const hasPublishSurface = hasPackagePublishSurface(packageJson);
|
|
246234
246562
|
const hasMavenRunnableEvidence = Boolean(
|
|
246235
|
-
maven && (hasMavenMainEntrypoint(workspaceRoot, candidate.path) || hasMavenConfiguredMainClassEntrypoint(workspaceRoot, candidate.path, maven.configuredMainClass) || maven.hasSpringBootPlugin && maven.hasSpringBootRepackageGoal && hasMavenMainEntrypoint(workspaceRoot, candidate.path) || maven.packaging === "war" && hasMavenMainEntrypoint(workspaceRoot, candidate.path))
|
|
246563
|
+
maven && (hasMavenMainEntrypoint(workspaceRoot, candidate.path) || hasMavenConfiguredMainClassEntrypoint(workspaceRoot, candidate.path, maven.configuredMainClass) || maven.configuredMainClass && maven.hasSpringBootStarterDependency || maven.hasSpringBootPlugin && maven.hasSpringBootRepackageGoal && hasMavenMainEntrypoint(workspaceRoot, candidate.path) || maven.packaging === "war" && hasMavenMainEntrypoint(workspaceRoot, candidate.path))
|
|
246236
246564
|
);
|
|
246237
246565
|
const hasMavenLibraryEvidence = Boolean(
|
|
246238
246566
|
maven && !hasMavenRunnableEvidence && (maven.packaging === "jar" || maven.packaging === "maven-plugin" || maven.packaging === "pom") && (hasMavenMainJvmSource(workspaceRoot, candidate.path) || maven.hasMainResources || maven.hasDependencyManagement || maven.hasSpringBootAutoconfigureDependency || maven.hasSpringBootAutoconfigureProcessor || hasMavenAutoConfigurationMetadata(workspaceRoot, candidate.path) || maven.hasDocumentationTooling || maven.hasTestJava || maven.hasTestResources)
|
|
@@ -246240,6 +246568,12 @@ function resolveKind(workspaceRoot, candidate, localProjectKinds) {
|
|
|
246240
246568
|
if (lowerPath.endsWith("/db") || lowerPath.endsWith("/database") || lowerPath.endsWith("/data")) {
|
|
246241
246569
|
return "data";
|
|
246242
246570
|
}
|
|
246571
|
+
if (nxRuntimeKind) {
|
|
246572
|
+
return nxRuntimeKind;
|
|
246573
|
+
}
|
|
246574
|
+
if (nxProjectType === "library") {
|
|
246575
|
+
return "library";
|
|
246576
|
+
}
|
|
246243
246577
|
if (hasMavenLibraryEvidence) {
|
|
246244
246578
|
return "library";
|
|
246245
246579
|
}
|
|
@@ -246251,6 +246585,12 @@ function resolveKind(workspaceRoot, candidate, localProjectKinds) {
|
|
|
246251
246585
|
return hasPublishSurface && !hasRunnableFrontendEvidence ? "library" : "frontend";
|
|
246252
246586
|
}
|
|
246253
246587
|
if (classification === "backend_app") {
|
|
246588
|
+
if (hasPublishSurface && dependencies.has("@nestjs/core") && !hasNestRuntimeEvidence) {
|
|
246589
|
+
return "library";
|
|
246590
|
+
}
|
|
246591
|
+
return "backend";
|
|
246592
|
+
}
|
|
246593
|
+
if (hasNestRuntimeEvidence) {
|
|
246254
246594
|
return "backend";
|
|
246255
246595
|
}
|
|
246256
246596
|
if (hasRunnableFrontendEvidence && localProjectKinds.primaryKind !== "backend" && localProjectKinds.primaryKind !== "service" && localProjectKinds.primaryKind !== "cli") {
|
|
@@ -246314,6 +246654,7 @@ function hasAnyToken(value, patterns) {
|
|
|
246314
246654
|
}
|
|
246315
246655
|
function classifyGovernanceRole(input2) {
|
|
246316
246656
|
const packageJson = readPackageJson(input2.workspaceRoot, input2.candidate.path);
|
|
246657
|
+
const projectJson = readProjectJson(input2.workspaceRoot, input2.candidate.path);
|
|
246317
246658
|
const maven = readMavenMetadata(input2.workspaceRoot, input2.candidate.path);
|
|
246318
246659
|
const evidence = [];
|
|
246319
246660
|
let supportScore = 0;
|
|
@@ -246327,11 +246668,18 @@ function classifyGovernanceRole(input2) {
|
|
|
246327
246668
|
const scripts = recordKeys(packageJson?.scripts);
|
|
246328
246669
|
const dependencies = recordKeys(packageJson?.dependencies);
|
|
246329
246670
|
const devDependencies = recordKeys(packageJson?.devDependencies);
|
|
246671
|
+
const projectTags = toStringArray(projectJson?.tags);
|
|
246672
|
+
const projectTargets = recordKeys(projectJson?.targets);
|
|
246330
246673
|
const scriptText = scripts.join(" ").toLowerCase();
|
|
246674
|
+
const projectMetadataText = `${projectTags.join(" ")} ${projectTargets.join(" ")}`.toLowerCase();
|
|
246331
246675
|
const dependencyText = [...dependencies, ...devDependencies].join(" ").toLowerCase();
|
|
246676
|
+
const hasRunnableFrontendEvidence = hasRunnableFrontendComponentEvidence(input2.workspaceRoot, input2.candidate.path);
|
|
246677
|
+
const hasNestRuntimeEvidence = hasNestRuntimeApplicationEvidence(input2.workspaceRoot, input2.candidate.path, packageJson);
|
|
246678
|
+
const nxRuntimeKind = classifyNxRuntimeKind(projectJson);
|
|
246679
|
+
const hasNxSupportOnlyEvidence = hasNxSupportOnlyProjectEvidence(projectJson);
|
|
246332
246680
|
const hasStrongSupportPath = hasAnyToken(pathText, [
|
|
246333
|
-
/(^|\/)(testing|test-plugins|cypress-tests|fixtures?|
|
|
246334
|
-
/(^|\/)(dev-server|scaffold|scaffolding|generators?|devkit|tooling|tools)(\/|$)/u
|
|
246681
|
+
/(^|\/)(testing|e2e-testing|test-plugins|cypress-tests|fixtures?|benchmarks?|smoke)(\/|$)/u,
|
|
246682
|
+
/(^|\/)(dev-server|scaffold|scaffolding|generators?|devkit|tooling|tools|templates?)(\/|$)/u
|
|
246335
246683
|
]);
|
|
246336
246684
|
const isPlainResourcesSurface = isUnderJvmResourceRoot4(pathText) && !hasRuntimeSourceFiles(input2.workspaceRoot, input2.candidate.path) && !packageJson && !maven;
|
|
246337
246685
|
const hasPublishSurface = hasPackagePublishSurface(packageJson);
|
|
@@ -246343,9 +246691,11 @@ function classifyGovernanceRole(input2) {
|
|
|
246343
246691
|
const hasMavenMainEntrypointEvidence = Boolean(maven && hasMavenMainEntrypoint(input2.workspaceRoot, input2.candidate.path));
|
|
246344
246692
|
const hasMavenMainJvmSourceEvidence = Boolean(maven && hasMavenMainJvmSource(input2.workspaceRoot, input2.candidate.path));
|
|
246345
246693
|
const hasMavenAutoConfigurationEvidence = Boolean(maven && (hasMavenAutoConfigurationMetadata(input2.workspaceRoot, input2.candidate.path) || maven.hasSpringBootAutoconfigureDependency || maven.hasSpringBootAutoconfigureProcessor));
|
|
246346
|
-
const hasMavenExecutableConfiguration = Boolean(maven && (hasMavenConfiguredMainClassEntrypoint(input2.workspaceRoot, input2.candidate.path, maven.configuredMainClass) || maven.hasSpringBootPlugin && maven.hasSpringBootRepackageGoal && hasMavenMainEntrypointEvidence || maven.packaging === "war" && hasMavenMainEntrypointEvidence));
|
|
246694
|
+
const hasMavenExecutableConfiguration = Boolean(maven && (hasMavenConfiguredMainClassEntrypoint(input2.workspaceRoot, input2.candidate.path, maven.configuredMainClass) || maven.configuredMainClass && maven.hasSpringBootStarterDependency || maven.hasSpringBootPlugin && maven.hasSpringBootRepackageGoal && hasMavenMainEntrypointEvidence || maven.packaging === "war" && hasMavenMainEntrypointEvidence));
|
|
246347
246695
|
const hasMavenRunnableApplicationEvidence = Boolean(hasMavenMainEntrypointEvidence || hasMavenExecutableConfiguration);
|
|
246348
|
-
const isMavenPomOnly = Boolean(
|
|
246696
|
+
const isMavenPomOnly = Boolean(
|
|
246697
|
+
maven?.packaging === "pom" && !hasMavenRunnableApplicationEvidence && !hasMavenMainSource && !hasMavenTestSource
|
|
246698
|
+
);
|
|
246349
246699
|
const hasMavenTestContext = hasAnyToken(pathText, [
|
|
246350
246700
|
/(^|\/)(test-framework|testsuite|integration-tests?|test-apps)(\/|$)/u
|
|
246351
246701
|
]) && (hasAnyToken(mavenMetadataText, [/\b(test|testsuite|test framework|arquillian|integration test)\b/u]) || Boolean(maven?.hasTestLifecycleConfiguration || maven?.hasArquillianEvidence || hasMavenTestSource));
|
|
@@ -246353,7 +246703,7 @@ function classifyGovernanceRole(input2) {
|
|
|
246353
246703
|
maven?.packaging === "pom" && maven.hasDependencyManagement && !hasMavenMainSource && hasAnyToken(mavenMetadataText, [/\b(bom|bill of materials|dependency management|platform)\b/u])
|
|
246354
246704
|
);
|
|
246355
246705
|
const hasMavenDistributionPackagingEvidence = Boolean(
|
|
246356
|
-
maven
|
|
246706
|
+
maven && !hasMavenMainSource && (maven.hasAssemblyPackagingConfiguration || maven.hasDeploySkipConfiguration && maven.hasDocumentationTooling || hasAnyToken(mavenMetadataText, [/\b(distribution|assembly|release package|packaging bundle)\b/u]))
|
|
246357
246707
|
);
|
|
246358
246708
|
const hasMavenStarterPackagingEvidence = Boolean(
|
|
246359
246709
|
maven && !hasMavenMainJvmSourceEvidence && hasAnyToken(`${pathText} ${mavenMetadataText}`, [/\bstarters?\b|\bspring-boot-starter\b|\bstarter[-\s]/u])
|
|
@@ -246376,6 +246726,22 @@ function classifyGovernanceRole(input2) {
|
|
|
246376
246726
|
runtimeScore += 1;
|
|
246377
246727
|
addEvidence6(evidence, `Runtime framework stack signal: ${input2.stack}`);
|
|
246378
246728
|
}
|
|
246729
|
+
if (hasNestRuntimeEvidence) {
|
|
246730
|
+
runtimeScore += 3;
|
|
246731
|
+
addEvidence6(evidence, "NestJS runtime application evidence");
|
|
246732
|
+
}
|
|
246733
|
+
if (input2.kind === "frontend" && hasRunnableFrontendEvidence) {
|
|
246734
|
+
runtimeScore += 3;
|
|
246735
|
+
addEvidence6(evidence, "Runnable frontend application evidence");
|
|
246736
|
+
}
|
|
246737
|
+
if (nxRuntimeKind) {
|
|
246738
|
+
runtimeScore += 3;
|
|
246739
|
+
addEvidence6(evidence, `Nx runtime project evidence: ${nxRuntimeKind}`);
|
|
246740
|
+
}
|
|
246741
|
+
if (hasNxSupportOnlyEvidence) {
|
|
246742
|
+
supportScore += 4;
|
|
246743
|
+
addEvidence6(evidence, "Nx project metadata indicates test/tooling-only workspace");
|
|
246744
|
+
}
|
|
246379
246745
|
if (hasPublishSurface && !isPrivate) {
|
|
246380
246746
|
runtimeScore += 1;
|
|
246381
246747
|
addEvidence6(evidence, "Published package surface signal");
|
|
@@ -246386,7 +246752,7 @@ function classifyGovernanceRole(input2) {
|
|
|
246386
246752
|
if (maven?.hasPom) {
|
|
246387
246753
|
addEvidence6(evidence, `Maven packaging ${maven.packaging ?? "jar"}`);
|
|
246388
246754
|
}
|
|
246389
|
-
if (maven &&
|
|
246755
|
+
if (maven && hasMavenRunnableApplicationEvidence) {
|
|
246390
246756
|
runtimeScore += 3;
|
|
246391
246757
|
addEvidence6(evidence, "Maven executable application evidence");
|
|
246392
246758
|
}
|
|
@@ -246400,25 +246766,41 @@ function classifyGovernanceRole(input2) {
|
|
|
246400
246766
|
if (hasMavenAutoConfigurationEvidence && !hasMavenRunnableApplicationEvidence) {
|
|
246401
246767
|
addEvidence6(evidence, "Maven Spring Boot auto-configuration/starter library evidence");
|
|
246402
246768
|
}
|
|
246403
|
-
if (hasAnyToken(descriptiveManifestText, [/\b(e2e|end-to-end|testing|test helper|test utilities|fixtures
|
|
246769
|
+
if (hasAnyToken(descriptiveManifestText, [/\b(e2e|end-to-end|testing|test helper|test utilities|fixtures?|test harness)\b/u])) {
|
|
246404
246770
|
supportScore += 3;
|
|
246405
246771
|
addEvidence6(evidence, "Package metadata describes test/support usage");
|
|
246406
246772
|
}
|
|
246773
|
+
if (hasAnyToken(`${packageName.toLowerCase()} ${projectMetadataText}`, [/\b(e2e|end-to-end|testing|test harness|scope:testing|test:ui|test:debug|test:report)\b/u]) && hasAnyToken(dependencyText, [/\b(?:playwright|@playwright\/test|cypress|vitest|jest|mocha)\b/u])) {
|
|
246774
|
+
supportScore += 4;
|
|
246775
|
+
addEvidence6(evidence, "Project metadata and dependencies indicate test-only workspace");
|
|
246776
|
+
}
|
|
246407
246777
|
if (hasAnyToken(descriptiveManifestText, [/\b(scaffold|scaffolding|generator|codegen|template|starter|create)\b/u])) {
|
|
246408
246778
|
supportScore += 3;
|
|
246409
246779
|
addEvidence6(evidence, "Package metadata describes scaffolding/generation usage");
|
|
246410
246780
|
}
|
|
246411
|
-
if (hasAnyToken(descriptiveManifestText, [/\b(dev server|development server|development tooling|tooling|devkit)\b/u])) {
|
|
246781
|
+
if (hasAnyToken(descriptiveManifestText, [/\b(dev server|development server|development tooling|tooling|devkit|lint rules?|linter|build tooling|repository tooling)\b/u])) {
|
|
246412
246782
|
supportScore += 2;
|
|
246413
246783
|
addEvidence6(evidence, "Package metadata describes development/tooling usage");
|
|
246414
246784
|
}
|
|
246415
246785
|
if (hasAnyToken(pathText, [
|
|
246416
|
-
/(^|\/)(test|tests|testing|__tests__|cypress|cypress-tests|fixtures?|
|
|
246417
|
-
/(^|\/)(dev-server|test-plugins|scaffold|scaffolding|generators?|devkit|tooling|tools)(\/|$)/u
|
|
246786
|
+
/(^|\/)(test|tests|testing|e2e-testing|__tests__|cypress|cypress-tests|fixtures?|benchmarks?|smoke)(\/|$)/u,
|
|
246787
|
+
/(^|\/)(dev-server|test-plugins|scaffold|scaffolding|generators?|devkit|tooling|tools|templates?)(\/|$)/u
|
|
246418
246788
|
])) {
|
|
246419
246789
|
supportScore += 1;
|
|
246420
246790
|
addEvidence6(evidence, "Path contains support/tooling role tokens");
|
|
246421
246791
|
}
|
|
246792
|
+
if (maven && hasStrongSupportPath && !hasMavenRunnableApplicationEvidence) {
|
|
246793
|
+
supportScore += 3;
|
|
246794
|
+
addEvidence6(evidence, "Maven module path and metadata indicate support/tooling role");
|
|
246795
|
+
}
|
|
246796
|
+
if (hasAnyToken(pathText, [/(^|\/)(?:src\/constants\/)?templates?(\/|$)/u])) {
|
|
246797
|
+
supportScore += 4;
|
|
246798
|
+
addEvidence6(evidence, "Nested scaffold/template source surface");
|
|
246799
|
+
}
|
|
246800
|
+
if (hasAnyToken(dependencyText, [/\b(?:eslint|oxlint|prettier|typescript-eslint|ts-morph|jscodeshift|schematics|yeoman)\b/u])) {
|
|
246801
|
+
supportScore += 2;
|
|
246802
|
+
addEvidence6(evidence, "Package dependencies indicate lint/build/generation tooling");
|
|
246803
|
+
}
|
|
246422
246804
|
if (scripts.length > 0 && scripts.every((script) => /^(test|e2e|smoke|bench|benchmark|lint|typecheck|dev|dev:|load-test|generate|scaffold)/u.test(script))) {
|
|
246423
246805
|
supportScore += 1;
|
|
246424
246806
|
addEvidence6(evidence, "Package scripts are dominated by development/test workflows");
|
|
@@ -246443,6 +246825,10 @@ function classifyGovernanceRole(input2) {
|
|
|
246443
246825
|
supportScore += 4;
|
|
246444
246826
|
addEvidence6(evidence, "Maven documentation tooling without JVM runtime source");
|
|
246445
246827
|
}
|
|
246828
|
+
if (maven?.hasDeploySkipConfiguration && !hasMavenMainJvmSourceEvidence && !hasMavenRunnableApplicationEvidence) {
|
|
246829
|
+
supportScore += 4;
|
|
246830
|
+
addEvidence6(evidence, "Maven deploy-skipped artifact without runtime source");
|
|
246831
|
+
}
|
|
246446
246832
|
if (hasMavenBomEvidence) {
|
|
246447
246833
|
supportScore += 5;
|
|
246448
246834
|
addEvidence6(evidence, "Maven BOM/dependency-management module without runtime source");
|
|
@@ -246471,6 +246857,10 @@ function classifyGovernanceRole(input2) {
|
|
|
246471
246857
|
supportScore += 4;
|
|
246472
246858
|
addEvidence6(evidence, "Maven starter/resource artifact without JVM runtime source");
|
|
246473
246859
|
}
|
|
246860
|
+
if (hasMavenDistributionPackagingEvidence) {
|
|
246861
|
+
supportScore += 4;
|
|
246862
|
+
addEvidence6(evidence, "Maven distribution/release packaging without runtime source");
|
|
246863
|
+
}
|
|
246474
246864
|
if (isPlainResourcesSurface) {
|
|
246475
246865
|
supportScore += 4;
|
|
246476
246866
|
addEvidence6(evidence, "Resources-only surface without runtime source or manifest evidence");
|
|
@@ -246493,7 +246883,7 @@ function classifyGovernanceRole(input2) {
|
|
|
246493
246883
|
supportScore += 3;
|
|
246494
246884
|
addEvidence6(evidence, "Maven documentation/build/distribution packaging evidence without runtime source");
|
|
246495
246885
|
}
|
|
246496
|
-
if (supportScore >= 3 && supportScore > runtimeScore || hasStrongSupportPath && supportScore >= 2 && runtimeScore <= 5 || maven?.packaging === "maven-plugin" && input2.candidate.path !== "." && supportScore >= 5 || maven && supportScore >= 5 && !
|
|
246886
|
+
if (supportScore >= 3 && supportScore > runtimeScore || hasStrongSupportPath && supportScore >= 2 && runtimeScore <= 5 || maven?.packaging === "maven-plugin" && input2.candidate.path !== "." && supportScore >= 5 || maven && supportScore >= 5 && !hasMavenMainJvmSourceEvidence && !hasMavenRunnableApplicationEvidence || maven && supportScore >= 4 && maven.hasDeploySkipConfiguration && !hasMavenMainJvmSourceEvidence && !hasMavenRunnableApplicationEvidence || maven && supportScore >= 4 && hasStrongSupportPath && !hasMavenMainJvmSourceEvidence && !hasMavenRunnableApplicationEvidence || maven && supportScore >= 4 && hasMavenTestContext || maven && supportScore >= 4 && hasMavenDistributionPackagingEvidence && hasAnyToken(mavenMetadataText, [/\b(docs?|documentation|metadata tests?|licenses?|maven plugins?|builds?)\b/u])) {
|
|
246497
246887
|
return {
|
|
246498
246888
|
governanceRole: "support",
|
|
246499
246889
|
governanceEvidence: uniqueSorted4(evidence),
|
|
@@ -250154,6 +250544,9 @@ function readFlagValue(args, flag) {
|
|
|
250154
250544
|
return value && value.length > 0 ? value : void 0;
|
|
250155
250545
|
}
|
|
250156
250546
|
async function readCliPackageVersion() {
|
|
250547
|
+
if ("0.2.6".trim().length > 0) {
|
|
250548
|
+
return "0.2.6".trim();
|
|
250549
|
+
}
|
|
250157
250550
|
const candidatePackageJsonPaths = [
|
|
250158
250551
|
path73.join(__dirname, "..", "package.json"),
|
|
250159
250552
|
path73.join(__dirname, "..", "..", "..", "..", "cli", "package.json")
|
package/package.json
CHANGED