@topogram/cli 0.3.76 → 0.3.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/adoption/plan/index.js +12 -1
- package/src/cli/commands/import/workspace.js +1 -0
- package/src/cli.js +3 -3
- package/src/import/core/runner/candidates.js +2 -0
- package/src/import/core/runner/reports.js +12 -5
- package/src/import/core/runner/tracks.js +1 -1
- package/src/import/core/shared/files.js +76 -1
- package/src/import/core/shared/next-app.js +2 -2
- package/src/import/core/shared/ui-routes.js +106 -0
- package/src/import/core/shared.js +8 -1
- package/src/import/enrichers/django-rest.js +4 -4
- package/src/import/enrichers/rails-controllers.js +3 -3
- package/src/import/enrichers/rails-models.js +3 -3
- package/src/import/extractors/api/aspnet-core.js +5 -5
- package/src/import/extractors/api/django-routes.js +5 -5
- package/src/import/extractors/api/express.js +4 -4
- package/src/import/extractors/api/fastify.js +7 -7
- package/src/import/extractors/api/flutter-dio.js +4 -4
- package/src/import/extractors/api/generic-route-fallback.js +3 -2
- package/src/import/extractors/api/graphql-code-first.js +3 -3
- package/src/import/extractors/api/graphql-sdl.js +5 -5
- package/src/import/extractors/api/jaxrs.js +3 -3
- package/src/import/extractors/api/micronaut.js +3 -3
- package/src/import/extractors/api/openapi-code.js +4 -4
- package/src/import/extractors/api/openapi.js +3 -3
- package/src/import/extractors/api/rails-routes.js +3 -3
- package/src/import/extractors/api/react-native-repository.js +3 -3
- package/src/import/extractors/api/retrofit.js +3 -3
- package/src/import/extractors/api/spring-web.js +3 -3
- package/src/import/extractors/api/swift-webapi.js +3 -3
- package/src/import/extractors/api/trpc.js +4 -4
- package/src/import/extractors/cli/generic.js +5 -4
- package/src/import/extractors/db/django-models.js +4 -4
- package/src/import/extractors/db/dotnet-models.js +4 -4
- package/src/import/extractors/db/drizzle.js +21 -9
- package/src/import/extractors/db/ef-core.js +5 -5
- package/src/import/extractors/db/flutter-entities.js +3 -3
- package/src/import/extractors/db/jpa.js +3 -3
- package/src/import/extractors/db/liquibase.js +3 -3
- package/src/import/extractors/db/maintained-seams.js +27 -4
- package/src/import/extractors/db/mybatis-xml.js +4 -4
- package/src/import/extractors/db/prisma.js +10 -3
- package/src/import/extractors/db/rails-schema.js +3 -3
- package/src/import/extractors/db/react-native-entities.js +3 -3
- package/src/import/extractors/db/room.js +5 -5
- package/src/import/extractors/db/snapshot.js +3 -3
- package/src/import/extractors/db/sql.js +3 -3
- package/src/import/extractors/db/swiftdata.js +3 -3
- package/src/import/extractors/ui/android-compose.js +4 -4
- package/src/import/extractors/ui/backend-only.js +3 -3
- package/src/import/extractors/ui/blazor.js +3 -3
- package/src/import/extractors/ui/flutter-screens.js +3 -3
- package/src/import/extractors/ui/maui-xaml.js +4 -4
- package/src/import/extractors/ui/next-app-router.js +26 -5
- package/src/import/extractors/ui/next-pages-router.js +34 -10
- package/src/import/extractors/ui/razor-pages.js +3 -3
- package/src/import/extractors/ui/react-native-screens.js +4 -4
- package/src/import/extractors/ui/react-router.js +34 -6
- package/src/import/extractors/ui/sveltekit.js +34 -6
- package/src/import/extractors/ui/swiftui.js +4 -3
- package/src/import/extractors/ui/uikit.js +3 -3
- package/src/workflows/reconcile/bundle-core/index.js +20 -1
- package/src/workflows/reconcile/candidate-model.js +13 -1
- package/src/workflows/reconcile/impacts/adoption-plan.js +13 -0
- package/src/workflows/reconcile/renderers.js +33 -0
- package/src/workflows/reconcile/workflow.js +2 -1
|
@@ -2,7 +2,7 @@ import path from "node:path";
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
dedupeCandidateRecords,
|
|
5
|
-
|
|
5
|
+
findPrimaryImportFiles,
|
|
6
6
|
inferApiCapabilityIdFromOperation,
|
|
7
7
|
inferApiEntityIdFromPath,
|
|
8
8
|
makeCandidateRecord,
|
|
@@ -263,8 +263,8 @@ export const fastifyExtractor = {
|
|
|
263
263
|
id: "api.fastify",
|
|
264
264
|
track: "api",
|
|
265
265
|
detect(context) {
|
|
266
|
-
const routeFiles =
|
|
267
|
-
const packageJsonFiles =
|
|
266
|
+
const routeFiles = findPrimaryImportFiles(context.paths, (filePath) => /src\/routes\/api\/.+\.(ts|js|mjs|cjs)$/i.test(filePath));
|
|
267
|
+
const packageJsonFiles = findPrimaryImportFiles(context.paths, (filePath) => /package\.json$/i.test(filePath));
|
|
268
268
|
const hasFastifyDependency = packageJsonFiles.some((filePath) => /"fastify"\s*:/.test(context.helpers.readTextIfExists(filePath) || ""));
|
|
269
269
|
return {
|
|
270
270
|
score: routeFiles.length > 0 && hasFastifyDependency ? 86 : 0,
|
|
@@ -272,16 +272,16 @@ export const fastifyExtractor = {
|
|
|
272
272
|
};
|
|
273
273
|
},
|
|
274
274
|
extract(context) {
|
|
275
|
-
const apiRoutesRoot =
|
|
276
|
-
? path.join(path.dirname(
|
|
275
|
+
const apiRoutesRoot = findPrimaryImportFiles(context.paths, (filePath) => /src\/routes\/api\/index\.(ts|js|mjs|cjs)$/i.test(filePath))[0]
|
|
276
|
+
? path.join(path.dirname(findPrimaryImportFiles(context.paths, (filePath) => /src\/routes\/api\/index\.(ts|js|mjs|cjs)$/i.test(filePath))[0]))
|
|
277
277
|
: null;
|
|
278
278
|
if (!apiRoutesRoot) {
|
|
279
279
|
return { findings: [], candidates: { capabilities: [], routes: [], stacks: [] } };
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
-
const routeFiles =
|
|
282
|
+
const routeFiles = findPrimaryImportFiles(context.paths, (filePath) => /src\/routes\/api\/.+\.(ts|js|mjs|cjs)$/i.test(filePath))
|
|
283
283
|
.filter((filePath) => !/\/autohooks\.(ts|js|mjs|cjs)$/i.test(filePath));
|
|
284
|
-
const schemaFiles =
|
|
284
|
+
const schemaFiles = findPrimaryImportFiles(context.paths, (filePath) => /src\/schemas\/.+\.(ts|js|mjs|cjs)$/i.test(filePath));
|
|
285
285
|
const namedSchemas = parseNamedTypeboxSchemas(schemaFiles, context.helpers.readTextIfExists);
|
|
286
286
|
|
|
287
287
|
const routes = [];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
canonicalCandidateTerm,
|
|
3
3
|
dedupeCandidateRecords,
|
|
4
|
-
|
|
4
|
+
findPrimaryImportFiles,
|
|
5
5
|
makeCandidateRecord,
|
|
6
6
|
pluralizeCandidateTerm,
|
|
7
7
|
relativeTo,
|
|
@@ -31,7 +31,7 @@ function capabilityIdFor(featureStem, methodName, httpMethod) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
function extractApiConfigPaths(context) {
|
|
34
|
-
const configFile =
|
|
34
|
+
const configFile = findPrimaryImportFiles(context.paths, (filePath) => /\/lib\/common\/network\/api_config\.dart$/i.test(filePath))[0];
|
|
35
35
|
const mapping = new Map();
|
|
36
36
|
if (!configFile) return mapping;
|
|
37
37
|
const text = context.helpers.readTextIfExists(configFile) || "";
|
|
@@ -87,7 +87,7 @@ export const flutterDioExtractor = {
|
|
|
87
87
|
id: "api.flutter-dio",
|
|
88
88
|
track: "api",
|
|
89
89
|
detect(context) {
|
|
90
|
-
const files =
|
|
90
|
+
const files = findPrimaryImportFiles(
|
|
91
91
|
context.paths,
|
|
92
92
|
(filePath) => /\/lib\/features\/.+\/data\/datasources\/.+_remote_data_source\.dart$/i.test(filePath)
|
|
93
93
|
);
|
|
@@ -98,7 +98,7 @@ export const flutterDioExtractor = {
|
|
|
98
98
|
};
|
|
99
99
|
},
|
|
100
100
|
extract(context) {
|
|
101
|
-
const files =
|
|
101
|
+
const files = findPrimaryImportFiles(
|
|
102
102
|
context.paths,
|
|
103
103
|
(filePath) => /\/lib\/features\/.+\/data\/datasources\/.+_remote_data_source\.dart$/i.test(filePath)
|
|
104
104
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { findPrimaryImportFiles, inferRouteAuthHint, inferRouteCapabilityId, inferRouteQueryParams, isPrimaryImportSource, makeCandidateRecord, normalizeOpenApiPath, relativeTo } from "../../core/shared.js";
|
|
2
2
|
|
|
3
3
|
function extractHandlerContext(text, handlerName) {
|
|
4
4
|
if (!handlerName) return "";
|
|
@@ -15,10 +15,11 @@ function extractHandlerContext(text, handlerName) {
|
|
|
15
15
|
|
|
16
16
|
function inferServerRoutes(context) {
|
|
17
17
|
const routes = [];
|
|
18
|
-
const routeFiles =
|
|
18
|
+
const routeFiles = findPrimaryImportFiles(
|
|
19
19
|
context.paths,
|
|
20
20
|
(filePath) =>
|
|
21
21
|
/\.(ts|tsx|js|jsx|mjs|cjs)$/.test(filePath) &&
|
|
22
|
+
isPrimaryImportSource(context.paths, filePath) &&
|
|
22
23
|
/(server|api|routes|src)/i.test(filePath)
|
|
23
24
|
);
|
|
24
25
|
for (const filePath of routeFiles) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
canonicalCandidateTerm,
|
|
3
3
|
dedupeCandidateRecords,
|
|
4
|
-
|
|
4
|
+
findPrimaryImportFiles,
|
|
5
5
|
idHintify,
|
|
6
6
|
makeCandidateRecord,
|
|
7
7
|
pluralizeCandidateTerm,
|
|
@@ -464,7 +464,7 @@ export const graphQlCodeFirstExtractor = {
|
|
|
464
464
|
id: "api.graphql-code-first",
|
|
465
465
|
track: "api",
|
|
466
466
|
detect(context) {
|
|
467
|
-
const files =
|
|
467
|
+
const files = findPrimaryImportFiles(context.paths, (filePath) => /(\/src\/.+|\/pages\/api\/.+)\.(ts|tsx|js|jsx)$/i.test(filePath));
|
|
468
468
|
const hasNestResolvers = files.some((filePath) => {
|
|
469
469
|
const text = readTextIfExists(filePath) || "";
|
|
470
470
|
return /@nestjs\/graphql/.test(text) && /@(Query|Mutation)\s*\(/.test(text);
|
|
@@ -489,7 +489,7 @@ export const graphQlCodeFirstExtractor = {
|
|
|
489
489
|
};
|
|
490
490
|
},
|
|
491
491
|
extract(context) {
|
|
492
|
-
const files =
|
|
492
|
+
const files = findPrimaryImportFiles(context.paths, (filePath) => /(\/src\/.+|\/pages\/api\/.+)\.(ts|tsx|js|jsx)$/i.test(filePath)).filter((filePath) => !/\.test\./i.test(filePath));
|
|
493
493
|
const nestTypes = parseNestTypes(files);
|
|
494
494
|
const pothosTypes = parsePothosTypes(files);
|
|
495
495
|
const nexusTypes = parseNexusTypes(files);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
canonicalCandidateTerm,
|
|
3
3
|
dedupeCandidateRecords,
|
|
4
|
-
|
|
4
|
+
findPrimaryImportFiles,
|
|
5
5
|
idHintify,
|
|
6
6
|
makeCandidateRecord,
|
|
7
7
|
pluralizeCandidateTerm,
|
|
@@ -174,7 +174,7 @@ function inferEndpointPath(context, graphqlFiles) {
|
|
|
174
174
|
return endpointMatch[1];
|
|
175
175
|
}
|
|
176
176
|
}
|
|
177
|
-
const packageJsonPath =
|
|
177
|
+
const packageJsonPath = findPrimaryImportFiles(context.paths, (filePath) => /package\.json$/i.test(filePath))[0];
|
|
178
178
|
const packageText = packageJsonPath ? readTextIfExists(packageJsonPath) : null;
|
|
179
179
|
if (packageText && /graphql-yoga|apollo-server|@apollo\/server/.test(packageText)) {
|
|
180
180
|
return "/graphql";
|
|
@@ -183,7 +183,7 @@ function inferEndpointPath(context, graphqlFiles) {
|
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
function extractGraphqlSchemaSources(context) {
|
|
186
|
-
const files =
|
|
186
|
+
const files = findPrimaryImportFiles(
|
|
187
187
|
context.paths,
|
|
188
188
|
(filePath) =>
|
|
189
189
|
/\/src\/.+\.(ts|tsx|js|jsx)$/i.test(filePath) ||
|
|
@@ -210,7 +210,7 @@ export const graphQlSdlExtractor = {
|
|
|
210
210
|
detect(context) {
|
|
211
211
|
const schemaSources = extractGraphqlSchemaSources(context);
|
|
212
212
|
const hasOperations = schemaSources.some(({ schema }) => /\btype\s+Query\b|\btype\s+Mutation\b/.test(schema));
|
|
213
|
-
const packageJsonPath =
|
|
213
|
+
const packageJsonPath = findPrimaryImportFiles(context.paths, (filePath) => /package\.json$/i.test(filePath))[0];
|
|
214
214
|
const packageText = packageJsonPath ? readTextIfExists(packageJsonPath) : "";
|
|
215
215
|
const hasGraphqlRuntime = /graphql-yoga|graphql|apollo-server|@apollo\/server/.test(packageText || "");
|
|
216
216
|
return {
|
|
@@ -220,7 +220,7 @@ export const graphQlSdlExtractor = {
|
|
|
220
220
|
},
|
|
221
221
|
extract(context) {
|
|
222
222
|
const schemaSources = extractGraphqlSchemaSources(context);
|
|
223
|
-
const endpointPath = inferEndpointPath(context,
|
|
223
|
+
const endpointPath = inferEndpointPath(context, findPrimaryImportFiles(context.paths, (filePath) => /\/src\/.+\.(ts|tsx|js|jsx)$/i.test(filePath)));
|
|
224
224
|
const mergedSchema = schemaSources.map(({ schema }) => schema).join("\n\n");
|
|
225
225
|
const blocks = parseGraphqlSchemaBlocks(mergedSchema);
|
|
226
226
|
const inputTypes = new Map([...blocks.entries()].filter(([, block]) => block.kind === "input"));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
dedupeCandidateRecords,
|
|
3
|
-
|
|
3
|
+
findPrimaryImportFiles,
|
|
4
4
|
inferApiEntityIdFromPath,
|
|
5
5
|
inferRouteCapabilityId,
|
|
6
6
|
makeCandidateRecord,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
} from "../../core/shared.js";
|
|
12
12
|
|
|
13
13
|
function buildJavaFileIndex(paths) {
|
|
14
|
-
const files =
|
|
14
|
+
const files = findPrimaryImportFiles(paths, (filePath) => /\.java$/i.test(filePath));
|
|
15
15
|
return files.map((filePath) => ({
|
|
16
16
|
filePath,
|
|
17
17
|
relativePath: relativeTo(paths.repoRoot, filePath),
|
|
@@ -253,7 +253,7 @@ export const jaxRsExtractor = {
|
|
|
253
253
|
id: "api.jaxrs",
|
|
254
254
|
track: "api",
|
|
255
255
|
detect(context) {
|
|
256
|
-
const javaFiles =
|
|
256
|
+
const javaFiles = findPrimaryImportFiles(context.paths, (filePath) => /\.java$/i.test(filePath));
|
|
257
257
|
const jaxrsCount = javaFiles.filter((filePath) => /@Path\(|@(GET|POST|PUT|PATCH|DELETE)\b/.test(readTextIfExists(filePath) || "")).length;
|
|
258
258
|
return {
|
|
259
259
|
score: jaxrsCount > 0 ? 92 : 0,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
dedupeCandidateRecords,
|
|
3
|
-
|
|
3
|
+
findPrimaryImportFiles,
|
|
4
4
|
inferApiEntityIdFromPath,
|
|
5
5
|
inferRouteCapabilityId,
|
|
6
6
|
makeCandidateRecord,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
} from "../../core/shared.js";
|
|
12
12
|
|
|
13
13
|
function buildJavaFileIndex(paths) {
|
|
14
|
-
const files =
|
|
14
|
+
const files = findPrimaryImportFiles(paths, (filePath) => /\.java$/i.test(filePath));
|
|
15
15
|
return files.map((filePath) => ({
|
|
16
16
|
filePath,
|
|
17
17
|
relativePath: relativeTo(paths.repoRoot, filePath),
|
|
@@ -163,7 +163,7 @@ export const micronautExtractor = {
|
|
|
163
163
|
id: "api.micronaut",
|
|
164
164
|
track: "api",
|
|
165
165
|
detect(context) {
|
|
166
|
-
const javaFiles =
|
|
166
|
+
const javaFiles = findPrimaryImportFiles(context.paths, (filePath) => /\.java$/i.test(filePath));
|
|
167
167
|
const count = javaFiles.filter((filePath) => /io\.micronaut\.http\.annotation|@Controller\(|@Get\(|@Post\(|@Put\(|@Delete\(/.test(readTextIfExists(filePath) || "")).length;
|
|
168
168
|
return {
|
|
169
169
|
score: count > 0 ? 95 : 0,
|
|
@@ -2,7 +2,7 @@ import path from "node:path";
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
dedupeCandidateRecords,
|
|
5
|
-
|
|
5
|
+
findPrimaryImportFiles,
|
|
6
6
|
inferApiCapabilityIdFromOperation,
|
|
7
7
|
inferApiEntityIdFromPath,
|
|
8
8
|
makeCandidateRecord,
|
|
@@ -183,15 +183,15 @@ export const openApiCodeExtractor = {
|
|
|
183
183
|
id: "api.openapi-code",
|
|
184
184
|
track: "api",
|
|
185
185
|
detect(context) {
|
|
186
|
-
const openApiFiles =
|
|
186
|
+
const openApiFiles = findPrimaryImportFiles(context.paths, (filePath) => /src\/docs\/openapi\.(ts|js|mjs|cjs)$/i.test(filePath));
|
|
187
187
|
return {
|
|
188
188
|
score: openApiFiles.length > 0 ? 92 : 0,
|
|
189
189
|
reasons: openApiFiles.length > 0 ? ["Found code-generated OpenAPI source"] : []
|
|
190
190
|
};
|
|
191
191
|
},
|
|
192
192
|
extract(context) {
|
|
193
|
-
const openApiFiles =
|
|
194
|
-
const schemaFile =
|
|
193
|
+
const openApiFiles = findPrimaryImportFiles(context.paths, (filePath) => /src\/docs\/openapi\.(ts|js|mjs|cjs)$/i.test(filePath));
|
|
194
|
+
const schemaFile = findPrimaryImportFiles(context.paths, (filePath) => /src\/docs\/openapi-schemas\.(ts|js|mjs|cjs)$/i.test(filePath))[0];
|
|
195
195
|
const schemaFields = schemaFile ? parseZodObjectSchemaFields(context.helpers.readTextIfExists(schemaFile) || "") : new Map();
|
|
196
196
|
const findings = [];
|
|
197
197
|
const candidates = { capabilities: [], routes: [], stacks: [] };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { findPrimaryImportFiles, isPrimaryImportSource, makeCandidateRecord, normalizeOpenApiPath, relativeTo, selectPreferredImportFiles, slugify, titleCase } from "../../core/shared.js";
|
|
2
2
|
|
|
3
3
|
function openApiRefName(ref) {
|
|
4
4
|
return typeof ref === "string" ? ref.split("/").pop() || null : null;
|
|
@@ -196,7 +196,7 @@ export const openApiExtractor = {
|
|
|
196
196
|
detect(context) {
|
|
197
197
|
const files = selectPreferredImportFiles(
|
|
198
198
|
context.paths,
|
|
199
|
-
|
|
199
|
+
findPrimaryImportFiles(context.paths, (filePath) => /(openapi|swagger)\.(json|ya?ml)$/i.test(filePath) && isPrimaryImportSource(context.paths, filePath)),
|
|
200
200
|
"openapi"
|
|
201
201
|
);
|
|
202
202
|
return {
|
|
@@ -207,7 +207,7 @@ export const openApiExtractor = {
|
|
|
207
207
|
extract(context) {
|
|
208
208
|
const openApiFiles = selectPreferredImportFiles(
|
|
209
209
|
context.paths,
|
|
210
|
-
|
|
210
|
+
findPrimaryImportFiles(context.paths, (filePath) => /(openapi|swagger)\.(json|ya?ml)$/i.test(filePath) && isPrimaryImportSource(context.paths, filePath)),
|
|
211
211
|
"openapi"
|
|
212
212
|
);
|
|
213
213
|
const findings = [];
|
|
@@ -2,7 +2,7 @@ import path from "node:path";
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
dedupeCandidateRecords,
|
|
5
|
-
|
|
5
|
+
findPrimaryImportFiles,
|
|
6
6
|
inferApiEntityIdFromPath,
|
|
7
7
|
inferRouteCapabilityId,
|
|
8
8
|
makeCandidateRecord,
|
|
@@ -167,14 +167,14 @@ export const railsRoutesExtractor = {
|
|
|
167
167
|
id: "api.rails-routes",
|
|
168
168
|
track: "api",
|
|
169
169
|
detect(context) {
|
|
170
|
-
const routeFiles =
|
|
170
|
+
const routeFiles = findPrimaryImportFiles(context.paths, (filePath) => /config\/routes\.rb$/i.test(filePath));
|
|
171
171
|
return {
|
|
172
172
|
score: routeFiles.length > 0 ? 90 : 0,
|
|
173
173
|
reasons: routeFiles.length > 0 ? ["Found Rails routes.rb"] : []
|
|
174
174
|
};
|
|
175
175
|
},
|
|
176
176
|
extract(context) {
|
|
177
|
-
const routeFiles =
|
|
177
|
+
const routeFiles = findPrimaryImportFiles(context.paths, (filePath) => /config\/routes\.rb$/i.test(filePath));
|
|
178
178
|
const findings = [];
|
|
179
179
|
const candidates = { capabilities: [], routes: [], stacks: [] };
|
|
180
180
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
canonicalCandidateTerm,
|
|
3
3
|
dedupeCandidateRecords,
|
|
4
|
-
|
|
4
|
+
findPrimaryImportFiles,
|
|
5
5
|
makeCandidateRecord,
|
|
6
6
|
pluralizeCandidateTerm,
|
|
7
7
|
relativeTo,
|
|
@@ -82,7 +82,7 @@ export const reactNativeRepositoryExtractor = {
|
|
|
82
82
|
id: "api.react-native-repository",
|
|
83
83
|
track: "api",
|
|
84
84
|
detect(context) {
|
|
85
|
-
const files =
|
|
85
|
+
const files = findPrimaryImportFiles(
|
|
86
86
|
context.paths,
|
|
87
87
|
(filePath) => /\/src\/.+\/infrastructure\/implementations\/.+Repository\.ts$/i.test(filePath)
|
|
88
88
|
);
|
|
@@ -93,7 +93,7 @@ export const reactNativeRepositoryExtractor = {
|
|
|
93
93
|
};
|
|
94
94
|
},
|
|
95
95
|
extract(context) {
|
|
96
|
-
const files =
|
|
96
|
+
const files = findPrimaryImportFiles(
|
|
97
97
|
context.paths,
|
|
98
98
|
(filePath) => /\/src\/.+\/infrastructure\/implementations\/.+Repository\.ts$/i.test(filePath)
|
|
99
99
|
);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
canonicalCandidateTerm,
|
|
3
3
|
dedupeCandidateRecords,
|
|
4
|
-
|
|
4
|
+
findPrimaryImportFiles,
|
|
5
5
|
makeCandidateRecord,
|
|
6
6
|
relativeTo,
|
|
7
7
|
titleCase
|
|
@@ -66,7 +66,7 @@ export const retrofitExtractor = {
|
|
|
66
66
|
id: "api.retrofit",
|
|
67
67
|
track: "api",
|
|
68
68
|
detect(context) {
|
|
69
|
-
const serviceFiles =
|
|
69
|
+
const serviceFiles = findPrimaryImportFiles(context.paths, (filePath) => /Service\.kt$/i.test(filePath) || /retrofit\/.+\.kt$/i.test(filePath));
|
|
70
70
|
const score = serviceFiles.some((filePath) => /@GET|@POST|@PUT|@PATCH|@DELETE/.test(context.helpers.readTextIfExists(filePath) || "")) ? 87 : 0;
|
|
71
71
|
return {
|
|
72
72
|
score,
|
|
@@ -74,7 +74,7 @@ export const retrofitExtractor = {
|
|
|
74
74
|
};
|
|
75
75
|
},
|
|
76
76
|
extract(context) {
|
|
77
|
-
const serviceFiles =
|
|
77
|
+
const serviceFiles = findPrimaryImportFiles(context.paths, (filePath) => /Service\.kt$/i.test(filePath) || /retrofit\/.+\.kt$/i.test(filePath));
|
|
78
78
|
const capabilities = [];
|
|
79
79
|
for (const filePath of serviceFiles) {
|
|
80
80
|
const provenance = relativeTo(context.paths.repoRoot, filePath);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
dedupeCandidateRecords,
|
|
3
|
-
|
|
3
|
+
findPrimaryImportFiles,
|
|
4
4
|
inferApiEntityIdFromPath,
|
|
5
5
|
inferRouteCapabilityId,
|
|
6
6
|
makeCandidateRecord,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
const JAVA_ANNOTATION_PATTERN = String.raw`@[\w.]+(?:\((?:[^()]|\([^)]*\))*\))?`;
|
|
14
14
|
|
|
15
15
|
function buildJavaFileIndex(paths) {
|
|
16
|
-
const files =
|
|
16
|
+
const files = findPrimaryImportFiles(paths, (filePath) => /\.java$/i.test(filePath));
|
|
17
17
|
return files.map((filePath) => ({
|
|
18
18
|
filePath,
|
|
19
19
|
relativePath: relativeTo(paths.repoRoot, filePath),
|
|
@@ -318,7 +318,7 @@ export const springWebExtractor = {
|
|
|
318
318
|
id: "api.spring-web",
|
|
319
319
|
track: "api",
|
|
320
320
|
detect(context) {
|
|
321
|
-
const javaFiles =
|
|
321
|
+
const javaFiles = findPrimaryImportFiles(context.paths, (filePath) => /\.java$/i.test(filePath));
|
|
322
322
|
const springCount = javaFiles.filter((filePath) => /@(RestController|Controller)|@(?:Get|Post|Put|Patch|Delete)Exchange|@(GetMapping|PostMapping|PutMapping|PatchMapping|DeleteMapping)|@RequestMapping/.test(readTextIfExists(filePath) || "")).length;
|
|
323
323
|
return {
|
|
324
324
|
score: springCount > 0 ? 90 : 0,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
canonicalCandidateTerm,
|
|
3
3
|
dedupeCandidateRecords,
|
|
4
|
-
|
|
4
|
+
findPrimaryImportFiles,
|
|
5
5
|
idHintify,
|
|
6
6
|
makeCandidateRecord,
|
|
7
7
|
relativeTo,
|
|
@@ -78,7 +78,7 @@ export const swiftWebApiExtractor = {
|
|
|
78
78
|
id: "api.swift-webapi",
|
|
79
79
|
track: "api",
|
|
80
80
|
detect(context) {
|
|
81
|
-
const files =
|
|
81
|
+
const files = findPrimaryImportFiles(context.paths, (filePath) => /WebRepository\.swift$/i.test(filePath) || /WebAPI\/.+\.swift$/i.test(filePath));
|
|
82
82
|
const score = files.some((filePath) => /APICall|URLSession/.test(context.helpers.readTextIfExists(filePath) || "")) ? 85 : 0;
|
|
83
83
|
return {
|
|
84
84
|
score,
|
|
@@ -86,7 +86,7 @@ export const swiftWebApiExtractor = {
|
|
|
86
86
|
};
|
|
87
87
|
},
|
|
88
88
|
extract(context) {
|
|
89
|
-
const files =
|
|
89
|
+
const files = findPrimaryImportFiles(context.paths, (filePath) => /WebAPI\/.+\.swift$/i.test(filePath))
|
|
90
90
|
.filter((filePath) => /struct\s+Real/.test(context.helpers.readTextIfExists(filePath) || ""));
|
|
91
91
|
const capabilities = [];
|
|
92
92
|
for (const filePath of files) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
dedupeCandidateRecords,
|
|
3
|
-
|
|
3
|
+
findPrimaryImportFiles,
|
|
4
4
|
inferApiEntityIdFromPath,
|
|
5
5
|
makeCandidateRecord,
|
|
6
6
|
pluralizeCandidateTerm,
|
|
@@ -156,15 +156,15 @@ export const trpcExtractor = {
|
|
|
156
156
|
id: "api.trpc",
|
|
157
157
|
track: "api",
|
|
158
158
|
detect(context) {
|
|
159
|
-
const routerFiles =
|
|
160
|
-
const trpcHandler =
|
|
159
|
+
const routerFiles = findPrimaryImportFiles(context.paths, (filePath) => /src\/server\/routers\/.+\.(ts|tsx|js|jsx)$/i.test(filePath));
|
|
160
|
+
const trpcHandler = findPrimaryImportFiles(context.paths, (filePath) => /src\/pages\/api\/trpc\/\[trpc\]\.(ts|tsx|js|jsx)$/i.test(filePath));
|
|
161
161
|
return {
|
|
162
162
|
score: routerFiles.length > 0 && trpcHandler.length > 0 ? 88 : 0,
|
|
163
163
|
reasons: routerFiles.length > 0 && trpcHandler.length > 0 ? ["Found tRPC router modules and Next.js tRPC handler"] : []
|
|
164
164
|
};
|
|
165
165
|
},
|
|
166
166
|
extract(context) {
|
|
167
|
-
const routerFiles =
|
|
167
|
+
const routerFiles = findPrimaryImportFiles(context.paths, (filePath) => /src\/server\/routers\/.+\.(ts|tsx|js|jsx)$/i.test(filePath))
|
|
168
168
|
.filter((filePath) => !/\/_app\.(ts|tsx|js|jsx)$/i.test(filePath) && !/\.test\./i.test(filePath));
|
|
169
169
|
const procedures = routerFiles.flatMap((filePath) => parseRouterProcedures(filePath, context.helpers.readTextIfExists(filePath) || ""));
|
|
170
170
|
const findings = [];
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
|
-
|
|
6
|
+
findPrimaryImportFiles,
|
|
7
7
|
idHintify,
|
|
8
|
+
isPrimaryImportSource,
|
|
8
9
|
makeCandidateRecord,
|
|
9
10
|
normalizeImportRelativePath,
|
|
10
11
|
readJsonIfExists,
|
|
@@ -33,7 +34,7 @@ function normalizePath(value) {
|
|
|
33
34
|
*/
|
|
34
35
|
function isAuthoritativeCliSource(paths, filePath) {
|
|
35
36
|
const normalized = normalizePath(normalizeImportRelativePath(paths, filePath));
|
|
36
|
-
return !NON_AUTHORITATIVE_CLI_PATH_PATTERN.test(normalized);
|
|
37
|
+
return isPrimaryImportSource(paths, filePath) && !NON_AUTHORITATIVE_CLI_PATH_PATTERN.test(normalized);
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
/**
|
|
@@ -250,9 +251,9 @@ function inspectPackageCliMetadata(context, packageFiles) {
|
|
|
250
251
|
* @returns {{ packageFiles: string[], sourceFiles: string[], binNames: Set<string>, findings: any[], provenance: string[] }}
|
|
251
252
|
*/
|
|
252
253
|
function discoverCliSources(context) {
|
|
253
|
-
const packageFiles =
|
|
254
|
+
const packageFiles = findPrimaryImportFiles(context.paths, (/** @type {string} */ filePath) => /package\.json$/i.test(filePath));
|
|
254
255
|
const packageMetadata = inspectPackageCliMetadata(context, packageFiles);
|
|
255
|
-
const sourceFiles =
|
|
256
|
+
const sourceFiles = findPrimaryImportFiles(context.paths, (/** @type {string} */ filePath) => {
|
|
256
257
|
const normalized = normalizePath(filePath);
|
|
257
258
|
if (!isAuthoritativeCliSource(context.paths, filePath)) {
|
|
258
259
|
return false;
|
|
@@ -3,7 +3,7 @@ import path from "node:path";
|
|
|
3
3
|
import {
|
|
4
4
|
canonicalCandidateTerm,
|
|
5
5
|
dedupeCandidateRecords,
|
|
6
|
-
|
|
6
|
+
findPrimaryImportFiles,
|
|
7
7
|
idHintify,
|
|
8
8
|
makeCandidateRecord,
|
|
9
9
|
relativeTo,
|
|
@@ -169,8 +169,8 @@ export const djangoModelsExtractor = {
|
|
|
169
169
|
id: "db.django-models",
|
|
170
170
|
track: "db",
|
|
171
171
|
detect(context) {
|
|
172
|
-
const modelFiles =
|
|
173
|
-
const manageFiles =
|
|
172
|
+
const modelFiles = findPrimaryImportFiles(context.paths, (filePath) => /\/models\.py$/i.test(filePath));
|
|
173
|
+
const manageFiles = findPrimaryImportFiles(context.paths, (filePath) => /\/manage\.py$/i.test(filePath));
|
|
174
174
|
const score = modelFiles.length > 0 && manageFiles.length > 0 ? 91 : 0;
|
|
175
175
|
return {
|
|
176
176
|
score,
|
|
@@ -178,7 +178,7 @@ export const djangoModelsExtractor = {
|
|
|
178
178
|
};
|
|
179
179
|
},
|
|
180
180
|
extract(context) {
|
|
181
|
-
const modelFiles =
|
|
181
|
+
const modelFiles = findPrimaryImportFiles(context.paths, (filePath) => /\/models\.py$/i.test(filePath));
|
|
182
182
|
const findings = [];
|
|
183
183
|
const candidates = { entities: [], enums: [], relations: [], indexes: [] };
|
|
184
184
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
canonicalCandidateTerm,
|
|
3
3
|
dedupeCandidateRecords,
|
|
4
|
-
|
|
4
|
+
findPrimaryImportFiles,
|
|
5
5
|
idHintify,
|
|
6
6
|
makeCandidateRecord,
|
|
7
7
|
relativeTo,
|
|
@@ -61,8 +61,8 @@ export const dotnetModelsExtractor = {
|
|
|
61
61
|
id: "db.dotnet-models",
|
|
62
62
|
track: "db",
|
|
63
63
|
detect(context) {
|
|
64
|
-
const modelFiles =
|
|
65
|
-
const csprojFiles =
|
|
64
|
+
const modelFiles = findPrimaryImportFiles(context.paths, (filePath) => /\/Models\/.+\.cs$/i.test(filePath));
|
|
65
|
+
const csprojFiles = findPrimaryImportFiles(context.paths, (filePath) => /\.csproj$/i.test(filePath));
|
|
66
66
|
const score = modelFiles.length > 0 && csprojFiles.length > 0 ? 78 : 0;
|
|
67
67
|
return {
|
|
68
68
|
score,
|
|
@@ -70,7 +70,7 @@ export const dotnetModelsExtractor = {
|
|
|
70
70
|
};
|
|
71
71
|
},
|
|
72
72
|
extract(context) {
|
|
73
|
-
const modelFiles =
|
|
73
|
+
const modelFiles = findPrimaryImportFiles(context.paths, (filePath) => /\/Models\/.+\.cs$/i.test(filePath));
|
|
74
74
|
const findings = [];
|
|
75
75
|
const entities = [];
|
|
76
76
|
for (const filePath of modelFiles) {
|
|
@@ -3,8 +3,9 @@ import path from "node:path";
|
|
|
3
3
|
import {
|
|
4
4
|
canonicalCandidateTerm,
|
|
5
5
|
dedupeCandidateRecords,
|
|
6
|
-
|
|
6
|
+
findPrimaryImportFiles,
|
|
7
7
|
idHintify,
|
|
8
|
+
isPrimaryImportSource,
|
|
8
9
|
makeCandidateRecord,
|
|
9
10
|
relativeTo,
|
|
10
11
|
slugify,
|
|
@@ -167,7 +168,10 @@ function parseDrizzleTables(schemaText) {
|
|
|
167
168
|
}
|
|
168
169
|
|
|
169
170
|
function drizzleConfigFiles(context) {
|
|
170
|
-
return
|
|
171
|
+
return findPrimaryImportFiles(context.paths, (filePath) =>
|
|
172
|
+
/drizzle\.config\.(ts|js|mjs|cjs)$/i.test(path.basename(filePath)) &&
|
|
173
|
+
isPrimaryImportSource(context.paths, filePath)
|
|
174
|
+
);
|
|
171
175
|
}
|
|
172
176
|
|
|
173
177
|
function configuredSchemaFiles(context, configFiles) {
|
|
@@ -176,7 +180,10 @@ function configuredSchemaFiles(context, configFiles) {
|
|
|
176
180
|
const configText = context.helpers.readTextIfExists(configFile) || "";
|
|
177
181
|
for (const match of configText.matchAll(/\bschema\s*:\s*["'`]([^"'`*]+)["'`]/g)) {
|
|
178
182
|
const absoluteSchemaPath = path.resolve(path.dirname(configFile), match[1]);
|
|
179
|
-
if (
|
|
183
|
+
if (
|
|
184
|
+
context.helpers.readTextIfExists(absoluteSchemaPath) !== null &&
|
|
185
|
+
isPrimaryImportSource(context.paths, absoluteSchemaPath)
|
|
186
|
+
) {
|
|
180
187
|
files.push(absoluteSchemaPath);
|
|
181
188
|
}
|
|
182
189
|
}
|
|
@@ -184,26 +191,31 @@ function configuredSchemaFiles(context, configFiles) {
|
|
|
184
191
|
return files;
|
|
185
192
|
}
|
|
186
193
|
|
|
194
|
+
function isDrizzleSchemaSource(context, filePath) {
|
|
195
|
+
const text = context.helpers.readTextIfExists(filePath) || "";
|
|
196
|
+
return /\b(?:pgTable|sqliteTable|mysqlTable)\s*\(/.test(text);
|
|
197
|
+
}
|
|
198
|
+
|
|
187
199
|
function findDrizzleSchemaFiles(context) {
|
|
188
200
|
const configFiles = drizzleConfigFiles(context);
|
|
189
|
-
const conventionalSchemaFiles =
|
|
190
|
-
/(?:^|\/)(?:src\/db\/schema|src\/schema|db\/schema|schema)\.(ts|js|mjs|cjs)$/i.test(relativeTo(context.paths.workspaceRoot, filePath).replaceAll(path.sep, "/"))
|
|
201
|
+
const conventionalSchemaFiles = findPrimaryImportFiles(context.paths, (filePath) =>
|
|
202
|
+
/(?:^|\/)(?:src\/db\/schema|src\/schema|db\/schema|schema)\.(ts|js|mjs|cjs)$/i.test(relativeTo(context.paths.workspaceRoot, filePath).replaceAll(path.sep, "/")) &&
|
|
203
|
+
isPrimaryImportSource(context.paths, filePath)
|
|
191
204
|
);
|
|
192
205
|
return [...new Set([
|
|
193
206
|
...configuredSchemaFiles(context, configFiles),
|
|
194
207
|
...conventionalSchemaFiles
|
|
195
|
-
])].sort();
|
|
208
|
+
])].filter((filePath) => isDrizzleSchemaSource(context, filePath)).sort();
|
|
196
209
|
}
|
|
197
210
|
|
|
198
211
|
export const drizzleExtractor = {
|
|
199
212
|
id: "db.drizzle",
|
|
200
213
|
track: "db",
|
|
201
214
|
detect(context) {
|
|
202
|
-
const hasConfig = drizzleConfigFiles(context).length > 0;
|
|
203
215
|
const hasSchema = findDrizzleSchemaFiles(context).length > 0;
|
|
204
216
|
return {
|
|
205
|
-
score:
|
|
206
|
-
reasons:
|
|
217
|
+
score: hasSchema ? 95 : 0,
|
|
218
|
+
reasons: hasSchema ? ["Found Drizzle schema source"] : []
|
|
207
219
|
};
|
|
208
220
|
},
|
|
209
221
|
extract(context) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
canonicalCandidateTerm,
|
|
3
3
|
dedupeCandidateRecords,
|
|
4
|
-
|
|
4
|
+
findPrimaryImportFiles,
|
|
5
5
|
makeCandidateRecord,
|
|
6
6
|
readTextIfExists,
|
|
7
7
|
relativeTo,
|
|
@@ -155,8 +155,8 @@ export const efCoreExtractor = {
|
|
|
155
155
|
id: "db.ef-core",
|
|
156
156
|
track: "db",
|
|
157
157
|
detect(context) {
|
|
158
|
-
const csprojFiles =
|
|
159
|
-
const dbContextFiles =
|
|
158
|
+
const csprojFiles = findPrimaryImportFiles(context.paths, (filePath) => /\.csproj$/i.test(filePath));
|
|
159
|
+
const dbContextFiles = findPrimaryImportFiles(context.paths, (filePath) => /DbContext|Context\.cs$/i.test(filePath));
|
|
160
160
|
const score = csprojFiles.length > 0 && dbContextFiles.some((filePath) => /DbContext/.test(readTextIfExists(filePath) || "")) ? 89 : 0;
|
|
161
161
|
return {
|
|
162
162
|
score,
|
|
@@ -164,8 +164,8 @@ export const efCoreExtractor = {
|
|
|
164
164
|
};
|
|
165
165
|
},
|
|
166
166
|
extract(context) {
|
|
167
|
-
const dbContextFiles =
|
|
168
|
-
const domainFiles =
|
|
167
|
+
const dbContextFiles = findPrimaryImportFiles(context.paths, (filePath) => /DbContext|Context\.cs$/i.test(filePath));
|
|
168
|
+
const domainFiles = findPrimaryImportFiles(context.paths, (filePath) => /\/Domain\/.+\.cs$/i.test(filePath));
|
|
169
169
|
const findings = [];
|
|
170
170
|
const candidates = { entities: [], enums: [], relations: [], indexes: [] };
|
|
171
171
|
|