@flaid/devmap 0.2.0
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/LICENSE +21 -0
- package/README.md +168 -0
- package/dist/ai/completion.d.ts +7 -0
- package/dist/ai/completion.d.ts.map +1 -0
- package/dist/ai/completion.js +27 -0
- package/dist/ai/completion.js.map +1 -0
- package/dist/ai/contextBuilder.d.ts +42 -0
- package/dist/ai/contextBuilder.d.ts.map +1 -0
- package/dist/ai/contextBuilder.js +632 -0
- package/dist/ai/contextBuilder.js.map +1 -0
- package/dist/ai/groq.d.ts +36 -0
- package/dist/ai/groq.d.ts.map +1 -0
- package/dist/ai/groq.js +368 -0
- package/dist/ai/groq.js.map +1 -0
- package/dist/ai/openrouter.d.ts +20 -0
- package/dist/ai/openrouter.d.ts.map +1 -0
- package/dist/ai/openrouter.js +187 -0
- package/dist/ai/openrouter.js.map +1 -0
- package/dist/ai/prompts.d.ts +7 -0
- package/dist/ai/prompts.d.ts.map +1 -0
- package/dist/ai/prompts.js +88 -0
- package/dist/ai/prompts.js.map +1 -0
- package/dist/ai/provider.d.ts +15 -0
- package/dist/ai/provider.d.ts.map +1 -0
- package/dist/ai/provider.js +28 -0
- package/dist/ai/provider.js.map +1 -0
- package/dist/ai/snapshotEnrichment.d.ts +4 -0
- package/dist/ai/snapshotEnrichment.d.ts.map +1 -0
- package/dist/ai/snapshotEnrichment.js +188 -0
- package/dist/ai/snapshotEnrichment.js.map +1 -0
- package/dist/ai/types.d.ts +29 -0
- package/dist/ai/types.d.ts.map +1 -0
- package/dist/ai/types.js +2 -0
- package/dist/ai/types.js.map +1 -0
- package/dist/analyzers/analysis/extractors/fallbackExtractor.d.ts +30 -0
- package/dist/analyzers/analysis/extractors/fallbackExtractor.d.ts.map +1 -0
- package/dist/analyzers/analysis/extractors/fallbackExtractor.js +114 -0
- package/dist/analyzers/analysis/extractors/fallbackExtractor.js.map +1 -0
- package/dist/analyzers/analysis/extractors/index.d.ts +16 -0
- package/dist/analyzers/analysis/extractors/index.d.ts.map +1 -0
- package/dist/analyzers/analysis/extractors/index.js +135 -0
- package/dist/analyzers/analysis/extractors/index.js.map +1 -0
- package/dist/analyzers/analysis/extractors/prismaExtractor.d.ts +15 -0
- package/dist/analyzers/analysis/extractors/prismaExtractor.d.ts.map +1 -0
- package/dist/analyzers/analysis/extractors/prismaExtractor.js +183 -0
- package/dist/analyzers/analysis/extractors/prismaExtractor.js.map +1 -0
- package/dist/analyzers/analysis/extractors/sqlExtractor.d.ts +14 -0
- package/dist/analyzers/analysis/extractors/sqlExtractor.d.ts.map +1 -0
- package/dist/analyzers/analysis/extractors/sqlExtractor.js +163 -0
- package/dist/analyzers/analysis/extractors/sqlExtractor.js.map +1 -0
- package/dist/analyzers/analysis/extractors/types.d.ts +76 -0
- package/dist/analyzers/analysis/extractors/types.d.ts.map +1 -0
- package/dist/analyzers/analysis/extractors/types.js +2 -0
- package/dist/analyzers/analysis/extractors/types.js.map +1 -0
- package/dist/analyzers/analysis/fileAnalysis.d.ts +36 -0
- package/dist/analyzers/analysis/fileAnalysis.d.ts.map +1 -0
- package/dist/analyzers/analysis/fileAnalysis.js +2 -0
- package/dist/analyzers/analysis/fileAnalysis.js.map +1 -0
- package/dist/analyzers/analysis/fileRole.d.ts +30 -0
- package/dist/analyzers/analysis/fileRole.d.ts.map +1 -0
- package/dist/analyzers/analysis/fileRole.js +242 -0
- package/dist/analyzers/analysis/fileRole.js.map +1 -0
- package/dist/analyzers/analysis/fileScanner.d.ts +10 -0
- package/dist/analyzers/analysis/fileScanner.d.ts.map +1 -0
- package/dist/analyzers/analysis/fileScanner.js +44 -0
- package/dist/analyzers/analysis/fileScanner.js.map +1 -0
- package/dist/analyzers/analysis/filterEngine.d.ts +2 -0
- package/dist/analyzers/analysis/filterEngine.d.ts.map +1 -0
- package/dist/analyzers/analysis/filterEngine.js +110 -0
- package/dist/analyzers/analysis/filterEngine.js.map +1 -0
- package/dist/analyzers/analysis/index.d.ts +12 -0
- package/dist/analyzers/analysis/index.d.ts.map +1 -0
- package/dist/analyzers/analysis/index.js +8 -0
- package/dist/analyzers/analysis/index.js.map +1 -0
- package/dist/analyzers/analysis/preprocessors/astroPreprocessor.d.ts +23 -0
- package/dist/analyzers/analysis/preprocessors/astroPreprocessor.d.ts.map +1 -0
- package/dist/analyzers/analysis/preprocessors/astroPreprocessor.js +40 -0
- package/dist/analyzers/analysis/preprocessors/astroPreprocessor.js.map +1 -0
- package/dist/analyzers/analysis/preprocessors/index.d.ts +5 -0
- package/dist/analyzers/analysis/preprocessors/index.d.ts.map +1 -0
- package/dist/analyzers/analysis/preprocessors/index.js +4 -0
- package/dist/analyzers/analysis/preprocessors/index.js.map +1 -0
- package/dist/analyzers/analysis/preprocessors/sveltePreprocessor.d.ts +27 -0
- package/dist/analyzers/analysis/preprocessors/sveltePreprocessor.d.ts.map +1 -0
- package/dist/analyzers/analysis/preprocessors/sveltePreprocessor.js +50 -0
- package/dist/analyzers/analysis/preprocessors/sveltePreprocessor.js.map +1 -0
- package/dist/analyzers/analysis/preprocessors/types.d.ts +45 -0
- package/dist/analyzers/analysis/preprocessors/types.d.ts.map +1 -0
- package/dist/analyzers/analysis/preprocessors/types.js +2 -0
- package/dist/analyzers/analysis/preprocessors/types.js.map +1 -0
- package/dist/analyzers/analysis/preprocessors/vuePreprocessor.d.ts +21 -0
- package/dist/analyzers/analysis/preprocessors/vuePreprocessor.d.ts.map +1 -0
- package/dist/analyzers/analysis/preprocessors/vuePreprocessor.js +44 -0
- package/dist/analyzers/analysis/preprocessors/vuePreprocessor.js.map +1 -0
- package/dist/analyzers/analysis/tsMorphAnalyzer.d.ts +10 -0
- package/dist/analyzers/analysis/tsMorphAnalyzer.d.ts.map +1 -0
- package/dist/analyzers/analysis/tsMorphAnalyzer.js +190 -0
- package/dist/analyzers/analysis/tsMorphAnalyzer.js.map +1 -0
- package/dist/analyzers/detectors/capabilityDetector.d.ts +28 -0
- package/dist/analyzers/detectors/capabilityDetector.d.ts.map +1 -0
- package/dist/analyzers/detectors/capabilityDetector.js +288 -0
- package/dist/analyzers/detectors/capabilityDetector.js.map +1 -0
- package/dist/analyzers/detectors/databaseDetector.d.ts +7 -0
- package/dist/analyzers/detectors/databaseDetector.d.ts.map +1 -0
- package/dist/analyzers/detectors/databaseDetector.js +71 -0
- package/dist/analyzers/detectors/databaseDetector.js.map +1 -0
- package/dist/analyzers/detectors/frameworkDetector.d.ts +22 -0
- package/dist/analyzers/detectors/frameworkDetector.d.ts.map +1 -0
- package/dist/analyzers/detectors/frameworkDetector.js +160 -0
- package/dist/analyzers/detectors/frameworkDetector.js.map +1 -0
- package/dist/analyzers/detectors/frontendFeatureDetector.d.ts +26 -0
- package/dist/analyzers/detectors/frontendFeatureDetector.d.ts.map +1 -0
- package/dist/analyzers/detectors/frontendFeatureDetector.js +269 -0
- package/dist/analyzers/detectors/frontendFeatureDetector.js.map +1 -0
- package/dist/analyzers/detectors/index.d.ts +11 -0
- package/dist/analyzers/detectors/index.d.ts.map +1 -0
- package/dist/analyzers/detectors/index.js +7 -0
- package/dist/analyzers/detectors/index.js.map +1 -0
- package/dist/analyzers/detectors/nestRouteDetector.d.ts +13 -0
- package/dist/analyzers/detectors/nestRouteDetector.d.ts.map +1 -0
- package/dist/analyzers/detectors/nestRouteDetector.js +69 -0
- package/dist/analyzers/detectors/nestRouteDetector.js.map +1 -0
- package/dist/analyzers/detectors/routeDetector.d.ts +22 -0
- package/dist/analyzers/detectors/routeDetector.d.ts.map +1 -0
- package/dist/analyzers/detectors/routeDetector.js +368 -0
- package/dist/analyzers/detectors/routeDetector.js.map +1 -0
- package/dist/analyzers/detectors/serviceDetector.d.ts +3 -0
- package/dist/analyzers/detectors/serviceDetector.d.ts.map +1 -0
- package/dist/analyzers/detectors/serviceDetector.js +81 -0
- package/dist/analyzers/detectors/serviceDetector.js.map +1 -0
- package/dist/analyzers/features/featureDetector.d.ts +22 -0
- package/dist/analyzers/features/featureDetector.d.ts.map +1 -0
- package/dist/analyzers/features/featureDetector.js +821 -0
- package/dist/analyzers/features/featureDetector.js.map +1 -0
- package/dist/analyzers/features/featureMerge.d.ts +65 -0
- package/dist/analyzers/features/featureMerge.d.ts.map +1 -0
- package/dist/analyzers/features/featureMerge.js +168 -0
- package/dist/analyzers/features/featureMerge.js.map +1 -0
- package/dist/analyzers/features/featureSimilarity.d.ts +152 -0
- package/dist/analyzers/features/featureSimilarity.d.ts.map +1 -0
- package/dist/analyzers/features/featureSimilarity.js +264 -0
- package/dist/analyzers/features/featureSimilarity.js.map +1 -0
- package/dist/analyzers/features/index.d.ts +6 -0
- package/dist/analyzers/features/index.d.ts.map +1 -0
- package/dist/analyzers/features/index.js +4 -0
- package/dist/analyzers/features/index.js.map +1 -0
- package/dist/analyzers/graph/dependencyGraph.d.ts +5 -0
- package/dist/analyzers/graph/dependencyGraph.d.ts.map +1 -0
- package/dist/analyzers/graph/dependencyGraph.js +88 -0
- package/dist/analyzers/graph/dependencyGraph.js.map +1 -0
- package/dist/analyzers/graph/dependencyMap.d.ts +43 -0
- package/dist/analyzers/graph/dependencyMap.d.ts.map +1 -0
- package/dist/analyzers/graph/dependencyMap.js +85 -0
- package/dist/analyzers/graph/dependencyMap.js.map +1 -0
- package/dist/analyzers/graph/entryPoints.d.ts +3 -0
- package/dist/analyzers/graph/entryPoints.d.ts.map +1 -0
- package/dist/analyzers/graph/entryPoints.js +21 -0
- package/dist/analyzers/graph/entryPoints.js.map +1 -0
- package/dist/analyzers/graph/index.d.ts +7 -0
- package/dist/analyzers/graph/index.d.ts.map +1 -0
- package/dist/analyzers/graph/index.js +5 -0
- package/dist/analyzers/graph/index.js.map +1 -0
- package/dist/analyzers/graph/sourceScope.d.ts +2 -0
- package/dist/analyzers/graph/sourceScope.d.ts.map +1 -0
- package/dist/analyzers/graph/sourceScope.js +30 -0
- package/dist/analyzers/graph/sourceScope.js.map +1 -0
- package/dist/analyzers/inference/domainInference.d.ts +58 -0
- package/dist/analyzers/inference/domainInference.d.ts.map +1 -0
- package/dist/analyzers/inference/domainInference.js +234 -0
- package/dist/analyzers/inference/domainInference.js.map +1 -0
- package/dist/analyzers/inference/index.d.ts +5 -0
- package/dist/analyzers/inference/index.d.ts.map +1 -0
- package/dist/analyzers/inference/index.js +3 -0
- package/dist/analyzers/inference/index.js.map +1 -0
- package/dist/analyzers/inference/ownershipTopology.d.ts +8 -0
- package/dist/analyzers/inference/ownershipTopology.d.ts.map +1 -0
- package/dist/analyzers/inference/ownershipTopology.js +65 -0
- package/dist/analyzers/inference/ownershipTopology.js.map +1 -0
- package/dist/analyzers/pipeline/analyzerRegistry.d.ts +9 -0
- package/dist/analyzers/pipeline/analyzerRegistry.d.ts.map +1 -0
- package/dist/analyzers/pipeline/analyzerRegistry.js +35 -0
- package/dist/analyzers/pipeline/analyzerRegistry.js.map +1 -0
- package/dist/analyzers/pipeline/heuristicAnalyzer.d.ts +12 -0
- package/dist/analyzers/pipeline/heuristicAnalyzer.d.ts.map +1 -0
- package/dist/analyzers/pipeline/heuristicAnalyzer.js +150 -0
- package/dist/analyzers/pipeline/heuristicAnalyzer.js.map +1 -0
- package/dist/analyzers/pipeline/index.d.ts +7 -0
- package/dist/analyzers/pipeline/index.d.ts.map +1 -0
- package/dist/analyzers/pipeline/index.js +5 -0
- package/dist/analyzers/pipeline/index.js.map +1 -0
- package/dist/analyzers/pipeline/projectMap.d.ts +120 -0
- package/dist/analyzers/pipeline/projectMap.d.ts.map +1 -0
- package/dist/analyzers/pipeline/projectMap.js +726 -0
- package/dist/analyzers/pipeline/projectMap.js.map +1 -0
- package/dist/analyzers/pipeline/projectMetadata.d.ts +19 -0
- package/dist/analyzers/pipeline/projectMetadata.d.ts.map +1 -0
- package/dist/analyzers/pipeline/projectMetadata.js +149 -0
- package/dist/analyzers/pipeline/projectMetadata.js.map +1 -0
- package/dist/analyzers/pipeline/reasonTags.d.ts +6 -0
- package/dist/analyzers/pipeline/reasonTags.d.ts.map +1 -0
- package/dist/analyzers/pipeline/reasonTags.js +6 -0
- package/dist/analyzers/pipeline/reasonTags.js.map +1 -0
- package/dist/analyzers/registry/ai-providers.d.ts +3 -0
- package/dist/analyzers/registry/ai-providers.d.ts.map +1 -0
- package/dist/analyzers/registry/ai-providers.js +94 -0
- package/dist/analyzers/registry/ai-providers.js.map +1 -0
- package/dist/analyzers/registry/analytics.d.ts +3 -0
- package/dist/analyzers/registry/analytics.d.ts.map +1 -0
- package/dist/analyzers/registry/analytics.js +15 -0
- package/dist/analyzers/registry/analytics.js.map +1 -0
- package/dist/analyzers/registry/auth.d.ts +3 -0
- package/dist/analyzers/registry/auth.d.ts.map +1 -0
- package/dist/analyzers/registry/auth.js +18 -0
- package/dist/analyzers/registry/auth.js.map +1 -0
- package/dist/analyzers/registry/background-jobs.d.ts +3 -0
- package/dist/analyzers/registry/background-jobs.d.ts.map +1 -0
- package/dist/analyzers/registry/background-jobs.js +14 -0
- package/dist/analyzers/registry/background-jobs.js.map +1 -0
- package/dist/analyzers/registry/caching.d.ts +3 -0
- package/dist/analyzers/registry/caching.d.ts.map +1 -0
- package/dist/analyzers/registry/caching.js +13 -0
- package/dist/analyzers/registry/caching.js.map +1 -0
- package/dist/analyzers/registry/cms-content.d.ts +3 -0
- package/dist/analyzers/registry/cms-content.d.ts.map +1 -0
- package/dist/analyzers/registry/cms-content.js +15 -0
- package/dist/analyzers/registry/cms-content.js.map +1 -0
- package/dist/analyzers/registry/database.d.ts +3 -0
- package/dist/analyzers/registry/database.d.ts.map +1 -0
- package/dist/analyzers/registry/database.js +13 -0
- package/dist/analyzers/registry/database.js.map +1 -0
- package/dist/analyzers/registry/email.d.ts +3 -0
- package/dist/analyzers/registry/email.d.ts.map +1 -0
- package/dist/analyzers/registry/email.js +19 -0
- package/dist/analyzers/registry/email.js.map +1 -0
- package/dist/analyzers/registry/file-upload.d.ts +3 -0
- package/dist/analyzers/registry/file-upload.d.ts.map +1 -0
- package/dist/analyzers/registry/file-upload.js +19 -0
- package/dist/analyzers/registry/file-upload.js.map +1 -0
- package/dist/analyzers/registry/firebase.d.ts +3 -0
- package/dist/analyzers/registry/firebase.d.ts.map +1 -0
- package/dist/analyzers/registry/firebase.js +8 -0
- package/dist/analyzers/registry/firebase.js.map +1 -0
- package/dist/analyzers/registry/index.d.ts +16 -0
- package/dist/analyzers/registry/index.d.ts.map +1 -0
- package/dist/analyzers/registry/index.js +88 -0
- package/dist/analyzers/registry/index.js.map +1 -0
- package/dist/analyzers/registry/internationalization.d.ts +3 -0
- package/dist/analyzers/registry/internationalization.d.ts.map +1 -0
- package/dist/analyzers/registry/internationalization.js +13 -0
- package/dist/analyzers/registry/internationalization.js.map +1 -0
- package/dist/analyzers/registry/logging-monitoring.d.ts +3 -0
- package/dist/analyzers/registry/logging-monitoring.d.ts.map +1 -0
- package/dist/analyzers/registry/logging-monitoring.js +14 -0
- package/dist/analyzers/registry/logging-monitoring.js.map +1 -0
- package/dist/analyzers/registry/notifications.d.ts +3 -0
- package/dist/analyzers/registry/notifications.d.ts.map +1 -0
- package/dist/analyzers/registry/notifications.js +14 -0
- package/dist/analyzers/registry/notifications.js.map +1 -0
- package/dist/analyzers/registry/payments.d.ts +3 -0
- package/dist/analyzers/registry/payments.d.ts.map +1 -0
- package/dist/analyzers/registry/payments.js +23 -0
- package/dist/analyzers/registry/payments.js.map +1 -0
- package/dist/analyzers/registry/rate-limiting.d.ts +3 -0
- package/dist/analyzers/registry/rate-limiting.d.ts.map +1 -0
- package/dist/analyzers/registry/rate-limiting.js +13 -0
- package/dist/analyzers/registry/rate-limiting.js.map +1 -0
- package/dist/analyzers/registry/search.d.ts +3 -0
- package/dist/analyzers/registry/search.d.ts.map +1 -0
- package/dist/analyzers/registry/search.js +15 -0
- package/dist/analyzers/registry/search.js.map +1 -0
- package/dist/analyzers/registry/testing.d.ts +3 -0
- package/dist/analyzers/registry/testing.d.ts.map +1 -0
- package/dist/analyzers/registry/testing.js +13 -0
- package/dist/analyzers/registry/testing.js.map +1 -0
- package/dist/analyzers/registry/types.d.ts +14 -0
- package/dist/analyzers/registry/types.d.ts.map +1 -0
- package/dist/analyzers/registry/types.js +2 -0
- package/dist/analyzers/registry/types.js.map +1 -0
- package/dist/cache/agentNavigation.d.ts +7 -0
- package/dist/cache/agentNavigation.d.ts.map +1 -0
- package/dist/cache/agentNavigation.js +253 -0
- package/dist/cache/agentNavigation.js.map +1 -0
- package/dist/cache/fileHash.d.ts +2 -0
- package/dist/cache/fileHash.d.ts.map +1 -0
- package/dist/cache/fileHash.js +5 -0
- package/dist/cache/fileHash.js.map +1 -0
- package/dist/cache/snapshot.d.ts +20 -0
- package/dist/cache/snapshot.d.ts.map +1 -0
- package/dist/cache/snapshot.js +184 -0
- package/dist/cache/snapshot.js.map +1 -0
- package/dist/commands/analyze.d.ts +12 -0
- package/dist/commands/analyze.d.ts.map +1 -0
- package/dist/commands/analyze.js +201 -0
- package/dist/commands/analyze.js.map +1 -0
- package/dist/commands/config.d.ts +10 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +65 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/doctor.d.ts +11 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +141 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/explain.d.ts +37 -0
- package/dist/commands/explain.d.ts.map +1 -0
- package/dist/commands/explain.js +101 -0
- package/dist/commands/explain.js.map +1 -0
- package/dist/commands/flow.d.ts +34 -0
- package/dist/commands/flow.d.ts.map +1 -0
- package/dist/commands/flow.js +151 -0
- package/dist/commands/flow.js.map +1 -0
- package/dist/commands/init.d.ts +16 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +197 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/map.d.ts +24 -0
- package/dist/commands/map.d.ts.map +1 -0
- package/dist/commands/map.js +282 -0
- package/dist/commands/map.js.map +1 -0
- package/dist/commands/onboarding.d.ts +36 -0
- package/dist/commands/onboarding.d.ts.map +1 -0
- package/dist/commands/onboarding.js +226 -0
- package/dist/commands/onboarding.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +104 -0
- package/dist/index.js.map +1 -0
- package/dist/onboarding/model.d.ts +27 -0
- package/dist/onboarding/model.d.ts.map +1 -0
- package/dist/onboarding/model.js +2 -0
- package/dist/onboarding/model.js.map +1 -0
- package/dist/onboarding/modelBuilder.d.ts +4 -0
- package/dist/onboarding/modelBuilder.d.ts.map +1 -0
- package/dist/onboarding/modelBuilder.js +330 -0
- package/dist/onboarding/modelBuilder.js.map +1 -0
- package/dist/utils/agentsFile.d.ts +6 -0
- package/dist/utils/agentsFile.d.ts.map +1 -0
- package/dist/utils/agentsFile.js +85 -0
- package/dist/utils/agentsFile.js.map +1 -0
- package/dist/utils/config.d.ts +20 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +88 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/devmapFile.d.ts +3 -0
- package/dist/utils/devmapFile.d.ts.map +1 -0
- package/dist/utils/devmapFile.js +43 -0
- package/dist/utils/devmapFile.js.map +1 -0
- package/dist/utils/errors.d.ts +8 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +92 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/gitignore.d.ts +2 -0
- package/dist/utils/gitignore.d.ts.map +1 -0
- package/dist/utils/gitignore.js +22 -0
- package/dist/utils/gitignore.js.map +1 -0
- package/dist/utils/help.d.ts +3 -0
- package/dist/utils/help.d.ts.map +1 -0
- package/dist/utils/help.js +19 -0
- package/dist/utils/help.js.map +1 -0
- package/dist/utils/mapRenderer.d.ts +39 -0
- package/dist/utils/mapRenderer.d.ts.map +1 -0
- package/dist/utils/mapRenderer.js +90 -0
- package/dist/utils/mapRenderer.js.map +1 -0
- package/dist/utils/markdownTerminal.d.ts +6 -0
- package/dist/utils/markdownTerminal.d.ts.map +1 -0
- package/dist/utils/markdownTerminal.js +153 -0
- package/dist/utils/markdownTerminal.js.map +1 -0
- package/dist/utils/output.d.ts +29 -0
- package/dist/utils/output.d.ts.map +1 -0
- package/dist/utils/output.js +108 -0
- package/dist/utils/output.js.map +1 -0
- package/dist/utils/packageMetadata.d.ts +2 -0
- package/dist/utils/packageMetadata.d.ts.map +1 -0
- package/dist/utils/packageMetadata.js +5 -0
- package/dist/utils/packageMetadata.js.map +1 -0
- package/dist/utils/prompt.d.ts +11 -0
- package/dist/utils/prompt.d.ts.map +1 -0
- package/dist/utils/prompt.js +81 -0
- package/dist/utils/prompt.js.map +1 -0
- package/dist/utils/slug.d.ts +2 -0
- package/dist/utils/slug.d.ts.map +1 -0
- package/dist/utils/slug.js +8 -0
- package/dist/utils/slug.js.map +1 -0
- package/dist/utils/targetResolver.d.ts +7 -0
- package/dist/utils/targetResolver.d.ts.map +1 -0
- package/dist/utils/targetResolver.js +15 -0
- package/dist/utils/targetResolver.js.map +1 -0
- package/dist/utils/welcome.d.ts +10 -0
- package/dist/utils/welcome.d.ts.map +1 -0
- package/dist/utils/welcome.js +80 -0
- package/dist/utils/welcome.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { PrismaExtractor } from "./prismaExtractor.js";
|
|
2
|
+
import { SQLExtractor } from "./sqlExtractor.js";
|
|
3
|
+
import { RouteFallbackExtractor } from "./fallbackExtractor.js";
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Extractor registry
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
/**
|
|
8
|
+
* EXTRACTORS — ordered fallback chain, diiterasi dari atas ke bawah.
|
|
9
|
+
*
|
|
10
|
+
* Tambah source baru = append extractor baru ke sini, tanpa ubah logic apapun.
|
|
11
|
+
* Orchestrator stop di extractor pertama yang canHandle() = true DAN extract() non-empty.
|
|
12
|
+
*
|
|
13
|
+
* Order penting: lebih reliable = lebih atas.
|
|
14
|
+
* 1. Prisma — high confidence, full field + relation data
|
|
15
|
+
* 2. [future] Drizzle → import { DrizzleExtractor } from "./drizzleExtractor.js"
|
|
16
|
+
* 3. [future] TypeORM → import { TypeORMExtractor } from "./typeormExtractor.js"
|
|
17
|
+
* 4. [future] Mongoose → import { MongooseExtractor } from "./mongooseExtractor.js"
|
|
18
|
+
* 5. SQL — raw pg/mysql2/better-sqlite3, table names as pseudo-entities
|
|
19
|
+
* (no field/relation data — lowest confidence of the schema sources,
|
|
20
|
+
* stays last so any ORM extractor above gets first refusal)
|
|
21
|
+
*/
|
|
22
|
+
const EXTRACTORS = [
|
|
23
|
+
new PrismaExtractor(),
|
|
24
|
+
// new DrizzleExtractor(),
|
|
25
|
+
// new TypeORMExtractor(),
|
|
26
|
+
// new MongooseExtractor(),
|
|
27
|
+
new SQLExtractor(),
|
|
28
|
+
];
|
|
29
|
+
const ROUTE_FALLBACK = new RouteFallbackExtractor();
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
// Main entry
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
/**
|
|
34
|
+
* extractEntities — scan files dan build entity graph.
|
|
35
|
+
*
|
|
36
|
+
* Fallback chain:
|
|
37
|
+
* 1. Iterate EXTRACTORS — stop di hasil pertama yang non-empty
|
|
38
|
+
* 2. Kalau semua kosong dan ada routes → route-hint fallback
|
|
39
|
+
* 3. Kalau routes juga kosong → return empty graph
|
|
40
|
+
*
|
|
41
|
+
* Relation graph di-build dari entity fields setelah semua entities terkumpul.
|
|
42
|
+
* Dedup entity dilakukan di sini (bukan di extractor) untuk handle Prisma multi-file schema.
|
|
43
|
+
*/
|
|
44
|
+
export function extractEntities(files, routes = []) {
|
|
45
|
+
// --- Schema-based sources ---
|
|
46
|
+
for (const extractor of EXTRACTORS) {
|
|
47
|
+
if (!extractor.canHandle(files))
|
|
48
|
+
continue;
|
|
49
|
+
const raw = extractor.extract(files);
|
|
50
|
+
if (raw.length === 0)
|
|
51
|
+
continue;
|
|
52
|
+
const entities = deduplicateEntities(raw);
|
|
53
|
+
const relations = buildRelationGraph(entities);
|
|
54
|
+
return {
|
|
55
|
+
entities,
|
|
56
|
+
relations,
|
|
57
|
+
entityNames: entities.map((e) => e.name),
|
|
58
|
+
source: extractor.name,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
// --- Route fallback: aktif kalau semua schema source kosong ---
|
|
62
|
+
if (routes.length > 0) {
|
|
63
|
+
const entities = ROUTE_FALLBACK.extract(routes);
|
|
64
|
+
if (entities.length > 0) {
|
|
65
|
+
return {
|
|
66
|
+
entities,
|
|
67
|
+
relations: [],
|
|
68
|
+
entityNames: entities.map((e) => e.name),
|
|
69
|
+
source: "route-hint",
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return { entities: [], relations: [], entityNames: [], source: "empty" };
|
|
74
|
+
}
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
// Relation graph builder
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
/**
|
|
79
|
+
* buildRelationGraph — derive semua relasi dari field isRelation = true.
|
|
80
|
+
*
|
|
81
|
+
* Rules:
|
|
82
|
+
* A.b B[] = one-to-many (A has many B)
|
|
83
|
+
* A.b B = one-to-one
|
|
84
|
+
* A.b B[] + B.a A[] = many-to-many
|
|
85
|
+
*
|
|
86
|
+
* Duplicate guard: many-to-many A↔B hanya disimpan sekali.
|
|
87
|
+
*/
|
|
88
|
+
function buildRelationGraph(entities) {
|
|
89
|
+
const relations = [];
|
|
90
|
+
const entitySet = new Set(entities.map((e) => e.name));
|
|
91
|
+
for (const entity of entities) {
|
|
92
|
+
for (const field of entity.fields) {
|
|
93
|
+
if (!field.isRelation || !entitySet.has(field.type))
|
|
94
|
+
continue;
|
|
95
|
+
const target = entities.find((e) => e.name === field.type);
|
|
96
|
+
const hasListBack = target?.fields.some((f) => f.type === entity.name && f.isList) ?? false;
|
|
97
|
+
let kind;
|
|
98
|
+
if (field.isList && hasListBack) {
|
|
99
|
+
kind = "many-to-many";
|
|
100
|
+
}
|
|
101
|
+
else if (field.isList) {
|
|
102
|
+
kind = "one-to-many";
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
kind = "one-to-one";
|
|
106
|
+
}
|
|
107
|
+
// Skip duplicate many-to-many (B→A sudah masuk waktu proses A→B)
|
|
108
|
+
const isDuplicate = relations.some((r) => r.kind === "many-to-many" &&
|
|
109
|
+
((r.from === entity.name && r.to === field.type) ||
|
|
110
|
+
(r.from === field.type && r.to === entity.name)));
|
|
111
|
+
if (!isDuplicate) {
|
|
112
|
+
relations.push({ from: entity.name, to: field.type, kind });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return relations;
|
|
117
|
+
}
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// Helpers
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
/**
|
|
122
|
+
* deduplicateEntities — filter duplicate entity names.
|
|
123
|
+
* Penting buat Prisma multi-file schema dimana model bisa didefinisi di file terpisah.
|
|
124
|
+
* First-seen wins.
|
|
125
|
+
*/
|
|
126
|
+
function deduplicateEntities(entities) {
|
|
127
|
+
const seen = new Set();
|
|
128
|
+
return entities.filter((e) => {
|
|
129
|
+
if (seen.has(e.name))
|
|
130
|
+
return false;
|
|
131
|
+
seen.add(e.name);
|
|
132
|
+
return true;
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/analyzers/analysis/extractors/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,GAAuB;IACrC,IAAI,eAAe,EAAE;IACrB,0BAA0B;IAC1B,0BAA0B;IAC1B,2BAA2B;IAC3B,IAAI,YAAY,EAAE;CACnB,CAAC;AAEF,MAAM,cAAc,GAAG,IAAI,sBAAsB,EAAE,CAAC;AAEpD,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E;;;;;;;;;;GAUG;AACH,MAAM,UAAU,eAAe,CAC7B,KAAoB,EACpB,SAAsB,EAAE;IAExB,+BAA+B;IAC/B,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC;YAAE,SAAS;QAE1C,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACrC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QAE/B,MAAM,QAAQ,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAC;QAC1C,MAAM,SAAS,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAE/C,OAAO;YACL,QAAQ;YACR,SAAS;YACT,WAAW,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YACxC,MAAM,EAAE,SAAS,CAAC,IAA6B;SAChD,CAAC;IACJ,CAAC;IAED,iEAAiE;IACjE,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAChD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,OAAO;gBACL,QAAQ;gBACR,SAAS,EAAE,EAAE;gBACb,WAAW,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;gBACxC,MAAM,EAAE,YAAY;aACrB,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AAC3E,CAAC;AAED,8EAA8E;AAC9E,yBAAyB;AACzB,8EAA8E;AAE9E;;;;;;;;;GASG;AACH,SAAS,kBAAkB,CAAC,QAAsB;IAChD,MAAM,SAAS,GAAmB,EAAE,CAAC;IACrC,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAEvD,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC9B,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClC,IAAI,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;gBAAE,SAAS;YAE9D,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC;YAC3D,MAAM,WAAW,GACf,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC;YAE1E,IAAI,IAA0B,CAAC;YAC/B,IAAI,KAAK,CAAC,MAAM,IAAI,WAAW,EAAE,CAAC;gBAChC,IAAI,GAAG,cAAc,CAAC;YACxB,CAAC;iBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;gBACxB,IAAI,GAAG,aAAa,CAAC;YACvB,CAAC;iBAAM,CAAC;gBACN,IAAI,GAAG,YAAY,CAAC;YACtB,CAAC;YAED,iEAAiE;YACjE,MAAM,WAAW,GAAG,SAAS,CAAC,IAAI,CAChC,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,IAAI,KAAK,cAAc;gBACzB,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,IAAI,CAAC;oBAC9C,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,CACrD,CAAC;YAEF,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E;;;;GAIG;AACH,SAAS,mBAAmB,CAAC,QAAsB;IACjD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QAC3B,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC;QACnC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ScannedFile } from "../index.js";
|
|
2
|
+
import type { EntityInfo, IEntityExtractor } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* PrismaExtractor — parse satu atau lebih .prisma files jadi list EntityInfo.
|
|
5
|
+
*
|
|
6
|
+
* Prisma supports multi-file schema via `prisma/` folder (Prisma 5+), jadi
|
|
7
|
+
* extract() iterate semua .prisma files dan merge hasilnya.
|
|
8
|
+
* Dedup dilakukan di orchestrator, bukan di sini.
|
|
9
|
+
*/
|
|
10
|
+
export declare class PrismaExtractor implements IEntityExtractor {
|
|
11
|
+
readonly name = "prisma";
|
|
12
|
+
canHandle(files: ScannedFile[]): boolean;
|
|
13
|
+
extract(files: ScannedFile[]): EntityInfo[];
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=prismaExtractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prismaExtractor.d.ts","sourceRoot":"","sources":["../../../../src/analyzers/analysis/extractors/prismaExtractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAA2B,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAqBxF;;;;;;GAMG;AACH,qBAAa,eAAgB,YAAW,gBAAgB;IACtD,QAAQ,CAAC,IAAI,YAAY;IAEzB,SAAS,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,OAAO;IAIxC,OAAO,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,UAAU,EAAE;CAa5C"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Constants
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
/**
|
|
5
|
+
* Tipe scalar bawaan Prisma — kalau field typenya ini, bukan relasi ke entity lain.
|
|
6
|
+
* https://www.prisma.io/docs/orm/reference/prisma-schema-reference#model-field-scalar-types
|
|
7
|
+
*/
|
|
8
|
+
const PRISMA_SCALAR_TYPES = new Set([
|
|
9
|
+
"String", "Boolean", "Int", "BigInt", "Float",
|
|
10
|
+
"Decimal", "DateTime", "Json", "Bytes",
|
|
11
|
+
// Prisma-specific (MongoDB)
|
|
12
|
+
"ObjectId",
|
|
13
|
+
]);
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Extractor
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
/**
|
|
18
|
+
* PrismaExtractor — parse satu atau lebih .prisma files jadi list EntityInfo.
|
|
19
|
+
*
|
|
20
|
+
* Prisma supports multi-file schema via `prisma/` folder (Prisma 5+), jadi
|
|
21
|
+
* extract() iterate semua .prisma files dan merge hasilnya.
|
|
22
|
+
* Dedup dilakukan di orchestrator, bukan di sini.
|
|
23
|
+
*/
|
|
24
|
+
export class PrismaExtractor {
|
|
25
|
+
name = "prisma";
|
|
26
|
+
canHandle(files) {
|
|
27
|
+
return files.some((f) => f.path.endsWith(".prisma"));
|
|
28
|
+
}
|
|
29
|
+
extract(files) {
|
|
30
|
+
const allEntities = [];
|
|
31
|
+
for (const file of files) {
|
|
32
|
+
if (!file.path.endsWith(".prisma"))
|
|
33
|
+
continue;
|
|
34
|
+
allEntities.push(...parsePrismaSchema(file.content));
|
|
35
|
+
}
|
|
36
|
+
// Build relations after all entities are parsed.
|
|
37
|
+
// We need the full entity name set to distinguish relations from scalars
|
|
38
|
+
// and to determine relation direction (one-to-many vs many-to-one).
|
|
39
|
+
return buildRelations(allEntities);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
// Parser internals
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
/**
|
|
46
|
+
* parsePrismaSchema — parse schema.prisma content jadi list EntityInfo.
|
|
47
|
+
*
|
|
48
|
+
* Prisma model syntax:
|
|
49
|
+
* model User {
|
|
50
|
+
* id String @id @default(cuid())
|
|
51
|
+
* email String @unique
|
|
52
|
+
* rooms Room[] ← relation one-to-many (User owns Rooms)
|
|
53
|
+
* workspace Workspace? ← relation one-to-one optional
|
|
54
|
+
* userId String ← FK scalar, bukan relasi langsung
|
|
55
|
+
* }
|
|
56
|
+
*/
|
|
57
|
+
function parsePrismaSchema(content) {
|
|
58
|
+
const entities = [];
|
|
59
|
+
// Match tiap model block — non-greedy biar gak overlap antar model
|
|
60
|
+
const modelPattern = /^model\s+(\w+)\s*\{([\s\S]*?)\n\}/gm;
|
|
61
|
+
let match = modelPattern.exec(content);
|
|
62
|
+
while (match) {
|
|
63
|
+
const name = match[1];
|
|
64
|
+
const body = match[2];
|
|
65
|
+
const fields = parsePrismaFields(body);
|
|
66
|
+
// relations di-populate di buildRelations() setelah semua entity ter-parse
|
|
67
|
+
entities.push({ name, fields, relations: [], source: "prisma" });
|
|
68
|
+
match = modelPattern.exec(content);
|
|
69
|
+
}
|
|
70
|
+
return entities;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* parsePrismaFields — extract field list dari body satu model block.
|
|
74
|
+
*
|
|
75
|
+
* Skip:
|
|
76
|
+
* - Baris kosong
|
|
77
|
+
* - Comment (//)
|
|
78
|
+
* - Block attributes (@@index, @@unique, @@map)
|
|
79
|
+
* - Inline attributes (@id, @default, dll) yang somehow lolos
|
|
80
|
+
*/
|
|
81
|
+
function parsePrismaFields(body) {
|
|
82
|
+
const fields = [];
|
|
83
|
+
// fieldName FieldType[]? @attributes...
|
|
84
|
+
// Capture: (1) fieldName, (2) fieldType, (3) [], (4) ?
|
|
85
|
+
const fieldPattern = /^\s+(\w+)\s+(\w+)(\[\])?(\?)?/gm;
|
|
86
|
+
let match = fieldPattern.exec(body);
|
|
87
|
+
while (match) {
|
|
88
|
+
const fieldName = match[1];
|
|
89
|
+
const fieldType = match[2];
|
|
90
|
+
const isList = Boolean(match[3]);
|
|
91
|
+
const isOptional = Boolean(match[4]);
|
|
92
|
+
// Skip attribute lines yang lolos regex
|
|
93
|
+
if (fieldName.startsWith("@")) {
|
|
94
|
+
match = fieldPattern.exec(body);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
// Tipe kapital + bukan scalar Prisma = relasi ke entity lain
|
|
98
|
+
const isRelation = isCapitalized(fieldType) && !PRISMA_SCALAR_TYPES.has(fieldType);
|
|
99
|
+
fields.push({ name: fieldName, type: fieldType, isRelation, isList, isOptional });
|
|
100
|
+
match = fieldPattern.exec(body);
|
|
101
|
+
}
|
|
102
|
+
return fields;
|
|
103
|
+
}
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
// Relation builder
|
|
106
|
+
//
|
|
107
|
+
// Prisma relasi selalu bidirectional — kedua sisi model punya field relasi.
|
|
108
|
+
// Kita derive arah relasi dari field type modifier:
|
|
109
|
+
//
|
|
110
|
+
// User { rooms Room[] } → User has many Room → one-to-many (User → Room)
|
|
111
|
+
// Room { user User } → Room belongs to User → many-to-one (Room → User)
|
|
112
|
+
// User { profile Profile? } → one-to-one optional
|
|
113
|
+
//
|
|
114
|
+
// Strategy: iterate tiap entity, cari field yang isRelation.
|
|
115
|
+
// - Field isList (Type[]) → from: thisEntity, to: fieldType, kind: one-to-many
|
|
116
|
+
// - Field !isList + optional → from: thisEntity, to: fieldType, kind: one-to-one
|
|
117
|
+
// - Field !isList + required → many-to-one (FK holder) — kita skip ini karena
|
|
118
|
+
// sisi lain (the "one") sudah generate one-to-many dari perspektifnya.
|
|
119
|
+
//
|
|
120
|
+
// Dedup: pakai Set string key biar relasi yang sama dari kedua sisi tidak double.
|
|
121
|
+
//
|
|
122
|
+
// Self-referential relations (Message → Message via sourceMessage/reminders):
|
|
123
|
+
// Field bertipe sama dengan entity sendiri → skip, ini bukan cross-entity relation.
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
function buildRelations(entities) {
|
|
126
|
+
const entityNames = new Set(entities.map((e) => e.name));
|
|
127
|
+
const seenRelations = new Set();
|
|
128
|
+
const allRelations = [];
|
|
129
|
+
for (const entity of entities) {
|
|
130
|
+
for (const field of entity.fields) {
|
|
131
|
+
if (!field.isRelation)
|
|
132
|
+
continue;
|
|
133
|
+
if (!entityNames.has(field.type))
|
|
134
|
+
continue;
|
|
135
|
+
// Skip self-referential — e.g. Message.sourceMessage: Message?
|
|
136
|
+
// These are valid Prisma patterns but not cross-entity ownership relations
|
|
137
|
+
if (field.type === entity.name)
|
|
138
|
+
continue;
|
|
139
|
+
if (field.isList) {
|
|
140
|
+
// Type[] → one-to-many: this entity owns many of field.type
|
|
141
|
+
// e.g. User.rooms Room[] → User → Room (one-to-many)
|
|
142
|
+
const key = `${entity.name}→${field.type}:one-to-many`;
|
|
143
|
+
if (!seenRelations.has(key)) {
|
|
144
|
+
seenRelations.add(key);
|
|
145
|
+
allRelations.push({ from: entity.name, to: field.type, kind: "one-to-many" });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
// Type or Type? (non-list) → this entity holds the FK (many-to-one side)
|
|
150
|
+
// We skip many-to-one here — the one-to-many from the parent already covers it.
|
|
151
|
+
// Exception: if there is NO corresponding list field on the other side,
|
|
152
|
+
// this might be a one-to-one — add it as such.
|
|
153
|
+
const otherEntity = entities.find((e) => e.name === field.type);
|
|
154
|
+
if (!otherEntity)
|
|
155
|
+
continue;
|
|
156
|
+
const otherSideHasList = otherEntity.fields.some((f) => f.isRelation && f.type === entity.name && f.isList);
|
|
157
|
+
if (!otherSideHasList) {
|
|
158
|
+
// No list on the other side → one-to-one
|
|
159
|
+
// Use alphabetical order to deduplicate bidirectional one-to-one fields
|
|
160
|
+
const [a, b] = [entity.name, field.type].sort();
|
|
161
|
+
const key = `${a}↔${b}:one-to-one`;
|
|
162
|
+
if (!seenRelations.has(key)) {
|
|
163
|
+
seenRelations.add(key);
|
|
164
|
+
allRelations.push({ from: entity.name, to: field.type, kind: "one-to-one" });
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// If other side has list → many-to-one, already handled from the list side → skip
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// Attach relations back to each entity
|
|
172
|
+
return entities.map((entity) => ({
|
|
173
|
+
...entity,
|
|
174
|
+
relations: allRelations.filter((r) => r.from === entity.name || r.to === entity.name),
|
|
175
|
+
}));
|
|
176
|
+
}
|
|
177
|
+
// ---------------------------------------------------------------------------
|
|
178
|
+
// Helpers
|
|
179
|
+
// ---------------------------------------------------------------------------
|
|
180
|
+
function isCapitalized(str) {
|
|
181
|
+
return str.length > 0 && str[0] === str[0].toUpperCase() && str[0] !== str[0].toLowerCase();
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=prismaExtractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prismaExtractor.js","sourceRoot":"","sources":["../../../../src/analyzers/analysis/extractors/prismaExtractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ScannedFile } from "../index.js";
|
|
2
|
+
import type { EntityInfo, IEntityExtractor } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* SQLExtractor — the "[future] SQL" slot already reserved in
|
|
5
|
+
* extractors/index.ts. Produces pseudo-entities (name only, no fields or
|
|
6
|
+
* relations — raw SQL has no schema metadata to read the way Prisma does)
|
|
7
|
+
* from table names referenced in query strings, for projects with no ORM.
|
|
8
|
+
*/
|
|
9
|
+
export declare class SQLExtractor implements IEntityExtractor {
|
|
10
|
+
readonly name = "sql";
|
|
11
|
+
canHandle(files: ScannedFile[]): boolean;
|
|
12
|
+
extract(files: ScannedFile[]): EntityInfo[];
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=sqlExtractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlExtractor.d.ts","sourceRoot":"","sources":["../../../../src/analyzers/analysis/extractors/sqlExtractor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAuI/D;;;;;GAKG;AACH,qBAAa,YAAa,YAAW,gBAAgB;IACnD,QAAQ,CAAC,IAAI,SAAS;IAEtB,SAAS,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,OAAO;IAIxC,OAAO,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,UAAU,EAAE;CA4B5C"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { Project, ScriptTarget, SyntaxKind } from "ts-morph";
|
|
2
|
+
import { singularize } from "./fallbackExtractor.js";
|
|
3
|
+
import { isArchitectureSource } from "../../graph/index.js";
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Constants
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
/**
|
|
8
|
+
* Raw SQL client packages. Deliberately narrow — these are the drivers
|
|
9
|
+
* actually used without an ORM layer on top. Drivers that only ever show up
|
|
10
|
+
* *underneath* an ORM (e.g. `pg` used by Drizzle) don't matter here: if an
|
|
11
|
+
* ORM extractor higher in the EXTRACTORS chain already found entities, this
|
|
12
|
+
* one never runs at all (orchestrator stops at first non-empty result).
|
|
13
|
+
*/
|
|
14
|
+
const RAW_SQL_IMPORTS = new Set([
|
|
15
|
+
"pg", "pg-promise",
|
|
16
|
+
"mysql2", "mysql2/promise", "mysql",
|
|
17
|
+
"better-sqlite3", "sqlite3", "node:sqlite",
|
|
18
|
+
]);
|
|
19
|
+
/**
|
|
20
|
+
* Table-like names that show up in real query strings but aren't domain
|
|
21
|
+
* entities — internal Postgres/SQLite catalogs and migration bookkeeping.
|
|
22
|
+
*/
|
|
23
|
+
const NON_ENTITY_TABLE_NAMES = new Set([
|
|
24
|
+
"information_schema", "pg_catalog", "pg_stat_activity",
|
|
25
|
+
"sqlite_master", "sqlite_sequence", "sqlite_temp_master",
|
|
26
|
+
"migrations", "schema_migrations", "knex_migrations", "_prisma_migrations",
|
|
27
|
+
]);
|
|
28
|
+
/**
|
|
29
|
+
* Common English function words that land right after from/into/update/join
|
|
30
|
+
* in ordinary UI copy — "Update your profile", "select a file from your
|
|
31
|
+
* computer" — but are never real table names. Without this, any project with
|
|
32
|
+
* a raw SQL client anywhere and normal SaaS/checkout copy elsewhere (confirm
|
|
33
|
+
* dialogs, toasts, form hints) produces bogus pseudo-entities like "Your".
|
|
34
|
+
*/
|
|
35
|
+
const ENGLISH_STOPWORDS = new Set([
|
|
36
|
+
"a", "an", "the", "this", "that", "these", "those",
|
|
37
|
+
"your", "my", "our", "their", "his", "her", "its",
|
|
38
|
+
"all", "any", "some", "each", "us", "you", "me", "them",
|
|
39
|
+
]);
|
|
40
|
+
/**
|
|
41
|
+
* Matches `from "pg"`, `require("mysql2")`, `require('better-sqlite3')`, etc.
|
|
42
|
+
* Content-based rather than relying on parsed imports, since IEntityExtractor
|
|
43
|
+
* only receives raw ScannedFile[] — same approach as the AI Integration
|
|
44
|
+
* content fallback in featureDetector.ts.
|
|
45
|
+
*/
|
|
46
|
+
function usesRawSqlClient(content) {
|
|
47
|
+
return [...RAW_SQL_IMPORTS].some((pkg) => {
|
|
48
|
+
const escaped = pkg.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
49
|
+
return new RegExp(`from\\s+["']${escaped}["']|require\\(\\s*["']${escaped}["']\\s*\\)`, "i").test(content);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Pull table names out of query strings via the SQL keywords that precede a
|
|
54
|
+
* table name in the vast majority of real queries. This is intentionally not
|
|
55
|
+
* a SQL parser — just enough to turn `SELECT * FROM users` into a "users"
|
|
56
|
+
* pseudo-entity.
|
|
57
|
+
*
|
|
58
|
+
* String *boundaries* come from a real AST (ts-morph — already a dependency,
|
|
59
|
+
* already used the same way in tsMorphAnalyzer.ts), not from regex-pairing
|
|
60
|
+
* quote characters. A naive `"([^"]*)"` scan pairs the Nth quote with the
|
|
61
|
+
* (N+1)th regardless of which statement they actually belong to, so a single
|
|
62
|
+
* apostrophe in a comment ("doesn't", "it's") throws off parity for
|
|
63
|
+
* everything after it — silently merging JSDoc prose and unrelated code into
|
|
64
|
+
* one fake "string" that gets scanned for SQL-shaped phrases. AST nodes don't
|
|
65
|
+
* have that failure mode: a StringLiteral node is exactly the source text
|
|
66
|
+
* between one real quote pair, comments and JSX text are different node
|
|
67
|
+
* kinds entirely, so this can't happen.
|
|
68
|
+
*/
|
|
69
|
+
const SQL_STATEMENT_PATTERN = /\b(?:select|insert|update|delete|with)\b/i;
|
|
70
|
+
const TABLE_NAME_PATTERN = /\b(?:from|into|update|join)\s+["'`]?([a-zA-Z_][a-zA-Z0-9_]*)["'`]?/gi;
|
|
71
|
+
// Real table identifiers are lowercase/snake_case (`users`, `order_items`) or,
|
|
72
|
+
// rarely, SCREAMING_CASE. A captured word that starts with a capital letter
|
|
73
|
+
// followed by a lowercase letter (`DevMap`, `Stripe`, `Your`) reads as a
|
|
74
|
+
// proper noun or a sentence's first word, not a table — the residual gap
|
|
75
|
+
// after the stopword list, which can only ever cover words we thought to
|
|
76
|
+
// list, not arbitrary product/brand names in CLI help text or UI copy.
|
|
77
|
+
const TITLE_CASE_PATTERN = /^[A-Z][a-z]/;
|
|
78
|
+
const SQL_SOURCE_EXTENSIONS = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
79
|
+
const literalProject = new Project({
|
|
80
|
+
useInMemoryFileSystem: true,
|
|
81
|
+
skipAddingFilesFromTsConfig: true,
|
|
82
|
+
compilerOptions: { allowJs: true, target: ScriptTarget.ES2022 }
|
|
83
|
+
});
|
|
84
|
+
function stringLiteralsIn(content) {
|
|
85
|
+
const literals = [];
|
|
86
|
+
try {
|
|
87
|
+
const sourceFile = literalProject.createSourceFile("__sql-scan.tsx", content, { overwrite: true });
|
|
88
|
+
for (const node of sourceFile.getDescendantsOfKind(SyntaxKind.StringLiteral)) {
|
|
89
|
+
literals.push(node.getLiteralText());
|
|
90
|
+
}
|
|
91
|
+
for (const node of sourceFile.getDescendantsOfKind(SyntaxKind.NoSubstitutionTemplateLiteral)) {
|
|
92
|
+
literals.push(node.getLiteralText());
|
|
93
|
+
}
|
|
94
|
+
literalProject.removeSourceFile(sourceFile);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// Best-effort: a file ts-morph can't parse just contributes no literals,
|
|
98
|
+
// same as a file with no SQL-shaped strings at all.
|
|
99
|
+
}
|
|
100
|
+
return literals;
|
|
101
|
+
}
|
|
102
|
+
function extractTableNames(file) {
|
|
103
|
+
const names = new Set();
|
|
104
|
+
if (!SQL_SOURCE_EXTENSIONS.has(file.extension))
|
|
105
|
+
return [];
|
|
106
|
+
for (const literal of stringLiteralsIn(file.content)) {
|
|
107
|
+
if (!SQL_STATEMENT_PATTERN.test(literal))
|
|
108
|
+
continue;
|
|
109
|
+
TABLE_NAME_PATTERN.lastIndex = 0;
|
|
110
|
+
let tableMatch = TABLE_NAME_PATTERN.exec(literal);
|
|
111
|
+
while (tableMatch) {
|
|
112
|
+
const raw = tableMatch[1];
|
|
113
|
+
const table = raw.toLowerCase();
|
|
114
|
+
if (!NON_ENTITY_TABLE_NAMES.has(table) && !ENGLISH_STOPWORDS.has(table) && !TITLE_CASE_PATTERN.test(raw)) {
|
|
115
|
+
names.add(table);
|
|
116
|
+
}
|
|
117
|
+
tableMatch = TABLE_NAME_PATTERN.exec(literal);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return [...names];
|
|
121
|
+
}
|
|
122
|
+
// ---------------------------------------------------------------------------
|
|
123
|
+
// Extractor
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
/**
|
|
126
|
+
* SQLExtractor — the "[future] SQL" slot already reserved in
|
|
127
|
+
* extractors/index.ts. Produces pseudo-entities (name only, no fields or
|
|
128
|
+
* relations — raw SQL has no schema metadata to read the way Prisma does)
|
|
129
|
+
* from table names referenced in query strings, for projects with no ORM.
|
|
130
|
+
*/
|
|
131
|
+
export class SQLExtractor {
|
|
132
|
+
name = "sql";
|
|
133
|
+
canHandle(files) {
|
|
134
|
+
return files.some((file) => isArchitectureSource(file.path) && usesRawSqlClient(file.content));
|
|
135
|
+
}
|
|
136
|
+
extract(files) {
|
|
137
|
+
const filesByTable = new Map();
|
|
138
|
+
const sourceFiles = files.filter((file) => isArchitectureSource(file.path));
|
|
139
|
+
for (const file of sourceFiles) {
|
|
140
|
+
for (const table of extractTableNames(file)) {
|
|
141
|
+
const fileSet = filesByTable.get(table) ?? new Set();
|
|
142
|
+
fileSet.add(file.path);
|
|
143
|
+
filesByTable.set(table, fileSet);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const filesByEntityName = new Map();
|
|
147
|
+
for (const [table, tableFiles] of filesByTable) {
|
|
148
|
+
const entityName = singularize(table);
|
|
149
|
+
const existing = filesByEntityName.get(entityName) ?? new Set();
|
|
150
|
+
for (const file of tableFiles)
|
|
151
|
+
existing.add(file);
|
|
152
|
+
filesByEntityName.set(entityName, existing);
|
|
153
|
+
}
|
|
154
|
+
return [...filesByEntityName.entries()].map(([name, sourceFiles]) => ({
|
|
155
|
+
name,
|
|
156
|
+
fields: [],
|
|
157
|
+
relations: [],
|
|
158
|
+
source: "sql",
|
|
159
|
+
sourceFiles: [...sourceFiles].sort()
|
|
160
|
+
}));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=sqlExtractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlExtractor.js","sourceRoot":"","sources":["../../../../src/analyzers/analysis/extractors/sqlExtractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { ScannedFile } from "../index.js";
|
|
2
|
+
import type { RouteInfo } from "../../detectors/index.js";
|
|
3
|
+
export type EntityInfo = {
|
|
4
|
+
name: string;
|
|
5
|
+
fields: FieldInfo[];
|
|
6
|
+
relations: RelationInfo[];
|
|
7
|
+
source: "prisma" | "sql" | "route-hint";
|
|
8
|
+
/** Files this entity was actually found in — set when the source has no
|
|
9
|
+
* reliable filename/path convention to fall back on (e.g. a "verses"
|
|
10
|
+
* table referenced inside src/routes/quran.ts has no file named verse.ts
|
|
11
|
+
* for the generic name-matching fallback to find). When present, this
|
|
12
|
+
* takes priority over that fallback. */
|
|
13
|
+
sourceFiles?: string[];
|
|
14
|
+
};
|
|
15
|
+
export type FieldInfo = {
|
|
16
|
+
name: string;
|
|
17
|
+
type: string;
|
|
18
|
+
isRelation: boolean;
|
|
19
|
+
isList: boolean;
|
|
20
|
+
isOptional: boolean;
|
|
21
|
+
};
|
|
22
|
+
export type RelationInfo = {
|
|
23
|
+
from: string;
|
|
24
|
+
to: string;
|
|
25
|
+
kind: "one-to-one" | "one-to-many" | "many-to-many";
|
|
26
|
+
};
|
|
27
|
+
export type EntityGraph = {
|
|
28
|
+
entities: EntityInfo[];
|
|
29
|
+
relations: RelationInfo[];
|
|
30
|
+
/** Flat list of entity names — shortcut buat featureDetector & capabilityDetector */
|
|
31
|
+
entityNames: string[];
|
|
32
|
+
/** Where entities came from — consumers dapat tau seberapa reliable data ini */
|
|
33
|
+
source: "prisma" | "sql" | "route-hint" | "empty";
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* IEntityExtractor — contract yang harus diimplementasi semua extractor.
|
|
37
|
+
*
|
|
38
|
+
* Setiap extractor bertanggung jawab atas satu source (Prisma, Drizzle, dll).
|
|
39
|
+
* Orchestrator di index.ts iterate extractor list dan stop di hasil pertama
|
|
40
|
+
* yang non-empty — ini yang bikin fallback chain bisa kerja tanpa if-else panjang.
|
|
41
|
+
*/
|
|
42
|
+
export interface IEntityExtractor {
|
|
43
|
+
/**
|
|
44
|
+
* Nama extractor ini — untuk logging / debug.
|
|
45
|
+
* Contoh: "prisma", "drizzle", "typeorm"
|
|
46
|
+
*/
|
|
47
|
+
readonly name: string;
|
|
48
|
+
/**
|
|
49
|
+
* canHandle — quick check apakah extractor ini relevan untuk file-file ini.
|
|
50
|
+
* Dipanggil sebelum extract() untuk short-circuit extractor yang tidak applicable.
|
|
51
|
+
*
|
|
52
|
+
* Contoh:
|
|
53
|
+
* Prisma extractor → return files.some(f => f.path.endsWith(".prisma"))
|
|
54
|
+
* Drizzle extractor → return files.some(f => isDrizzleSchemaFile(f))
|
|
55
|
+
*/
|
|
56
|
+
canHandle(files: ScannedFile[]): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* extract — parse files dan return list EntityInfo.
|
|
59
|
+
* Hanya dipanggil kalau canHandle() return true.
|
|
60
|
+
*
|
|
61
|
+
* Return [] kalau parse gagal / tidak ada entity ditemukan —
|
|
62
|
+
* orchestrator akan lanjut ke extractor berikutnya.
|
|
63
|
+
*/
|
|
64
|
+
extract(files: ScannedFile[]): EntityInfo[];
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* IRouteFallbackExtractor — contract khusus route-hint extractor.
|
|
68
|
+
*
|
|
69
|
+
* Dipisah dari IEntityExtractor karena input-nya berbeda (RouteInfo[] bukan ScannedFile[]).
|
|
70
|
+
* Orchestrator panggil ini hanya kalau semua IEntityExtractor return kosong.
|
|
71
|
+
*/
|
|
72
|
+
export interface IRouteFallbackExtractor {
|
|
73
|
+
readonly name: string;
|
|
74
|
+
extract(routes: RouteInfo[]): EntityInfo[];
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/analyzers/analysis/extractors/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAM1D,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,MAAM,EAAE,QAAQ,GAAG,KAAK,GAAG,YAAY,CAAC;IACxC;;;;6CAIyC;IACzC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,YAAY,GAAG,aAAa,GAAG,cAAc,CAAC;CACrD,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,qFAAqF;IACrF,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,gFAAgF;IAChF,MAAM,EAAE,QAAQ,GAAG,KAAK,GAAG,YAAY,GAAG,OAAO,CAAC;CACnD,CAAC;AAMF;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;;;;;;OAOG;IACH,SAAS,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;IAEzC;;;;;;OAMG;IACH,OAAO,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,UAAU,EAAE,CAAC;CAC7C;AAED;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,UAAU,EAAE,CAAC;CAC5C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/analyzers/analysis/extractors/types.ts"],"names":[],"mappings":""}
|