mirror of
https://github.com/Egonex-AI/Understand-Anything.git
synced 2026-06-22 10:58:03 +08:00
feat: language-agnostic analysis with config-driven registry and framework detection
Replace the TypeScript/JavaScript-biased analysis pipeline with a truly language-agnostic system. The core architecture was already language-neutral (graph schema, dashboard, search) — the bias lived in agent prompts, tree-sitter plugin, and language-lesson system. Core changes: - LanguageConfig + FrameworkConfig types with Zod validation - LanguageRegistry (12 languages) and FrameworkRegistry (10 frameworks) - Config-driven TreeSitterPlugin replacing hardcoded TS/JS grammars - PluginRegistry now delegates to LanguageRegistry for extension mapping - Language-lesson system uses config for display names and concepts Prompt system: - SKILL.md generalized: dynamic injection of language snippets and framework addendums instead of hardcoded if/else conditionals - 12 language prompt snippets (languages/*.md) with concepts, patterns, frameworks per language - 10 framework addendums (frameworks/*.md) with canonical file roles, edge patterns, architectural layers — Django/FastAPI/Flask preserved and split, plus React/Next.js/Express/Vue/Spring/Rails/Gin added - Extended entry points, directory patterns, and test patterns across all 12 language ecosystems in base prompts
This commit is contained in:
@@ -46,3 +46,36 @@ An open-source tool combining LLM intelligence + static analysis to produce inte
|
||||
When pushing to remote, bump the version in **both** of these files (keep them in sync):
|
||||
- `understand-anything-plugin/package.json` → `"version"` field
|
||||
- `.claude-plugin/marketplace.json` → `plugins[0].version` field
|
||||
|
||||
## Testing Local Plugin Changes
|
||||
|
||||
Claude Code caches installed plugins at `~/.claude/plugins/cache/understand-anything/understand-anything/<version>/`. Symlinks don't work because Claude's Search/Glob tools can't follow them. To test local changes:
|
||||
|
||||
1. **Build the packages:**
|
||||
```bash
|
||||
pnpm --filter @understand-anything/core build
|
||||
pnpm --filter @understand-anything/skill build
|
||||
```
|
||||
|
||||
2. **Find the installed version** (must match what the marketplace currently serves):
|
||||
```bash
|
||||
ls ~/.claude/plugins/cache/understand-anything/understand-anything/
|
||||
```
|
||||
|
||||
3. **Copy your local plugin into the cache**, replacing `<VERSION>` with the version from step 2:
|
||||
```bash
|
||||
rm -rf ~/.claude/plugins/cache/understand-anything/understand-anything/<VERSION>
|
||||
cp -R ./understand-anything-plugin ~/.claude/plugins/cache/understand-anything/understand-anything/<VERSION>
|
||||
```
|
||||
|
||||
4. **Start a fresh Claude Code session** (existing sessions cache the old prompts in context).
|
||||
|
||||
5. **Run `/understand --full`** in the target project to verify.
|
||||
|
||||
**Re-sync after further changes:**
|
||||
```bash
|
||||
pnpm --filter @understand-anything/core build && \
|
||||
cp -R ./understand-anything-plugin/* ~/.claude/plugins/cache/understand-anything/understand-anything/<VERSION>/
|
||||
```
|
||||
|
||||
**To revert to upstream:** Uninstall and reinstall the plugin from the marketplace — it repopulates the cache from the upstream repo.
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
"./schema": {
|
||||
"types": "./dist/schema.d.ts",
|
||||
"default": "./dist/schema.js"
|
||||
},
|
||||
"./languages": {
|
||||
"types": "./dist/languages/index.d.ts",
|
||||
"default": "./dist/languages/index.js"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { FrameworkRegistry } from "../languages/framework-registry.js";
|
||||
import { djangoConfig } from "../languages/frameworks/django.js";
|
||||
import { reactConfig } from "../languages/frameworks/react.js";
|
||||
|
||||
describe("FrameworkRegistry", () => {
|
||||
it("registers and retrieves a framework config by id", () => {
|
||||
const registry = new FrameworkRegistry();
|
||||
registry.register(djangoConfig);
|
||||
expect(registry.getById("django")?.displayName).toBe("Django");
|
||||
});
|
||||
|
||||
it("retrieves frameworks for a language", () => {
|
||||
const registry = new FrameworkRegistry();
|
||||
registry.register(djangoConfig);
|
||||
registry.register(reactConfig);
|
||||
const pythonFrameworks = registry.getForLanguage("python");
|
||||
expect(pythonFrameworks).toHaveLength(1);
|
||||
expect(pythonFrameworks[0].id).toBe("django");
|
||||
});
|
||||
|
||||
it("returns empty array for unknown language", () => {
|
||||
const registry = new FrameworkRegistry();
|
||||
registry.register(djangoConfig);
|
||||
expect(registry.getForLanguage("haskell")).toEqual([]);
|
||||
});
|
||||
|
||||
describe("detectFrameworks", () => {
|
||||
it("detects Django from requirements.txt", () => {
|
||||
const registry = new FrameworkRegistry();
|
||||
registry.register(djangoConfig);
|
||||
const detected = registry.detectFrameworks({
|
||||
"requirements.txt": "django==4.2\ncelery==5.3\n",
|
||||
});
|
||||
expect(detected).toHaveLength(1);
|
||||
expect(detected[0].id).toBe("django");
|
||||
});
|
||||
|
||||
it("detects React from package.json", () => {
|
||||
const registry = new FrameworkRegistry();
|
||||
registry.register(reactConfig);
|
||||
const detected = registry.detectFrameworks({
|
||||
"package.json": '{"dependencies": {"react": "^18.2.0", "react-dom": "^18.2.0"}}',
|
||||
});
|
||||
expect(detected).toHaveLength(1);
|
||||
expect(detected[0].id).toBe("react");
|
||||
});
|
||||
|
||||
it("detection is case-insensitive", () => {
|
||||
const registry = new FrameworkRegistry();
|
||||
registry.register(djangoConfig);
|
||||
const detected = registry.detectFrameworks({
|
||||
"requirements.txt": "Django==4.2\n",
|
||||
});
|
||||
expect(detected).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("returns empty array when no frameworks match", () => {
|
||||
const registry = new FrameworkRegistry();
|
||||
registry.register(djangoConfig);
|
||||
const detected = registry.detectFrameworks({
|
||||
"requirements.txt": "requests==2.31\n",
|
||||
});
|
||||
expect(detected).toEqual([]);
|
||||
});
|
||||
|
||||
it("returns empty array for empty manifests", () => {
|
||||
const registry = new FrameworkRegistry();
|
||||
registry.register(djangoConfig);
|
||||
expect(registry.detectFrameworks({})).toEqual([]);
|
||||
});
|
||||
|
||||
it("does not duplicate detected frameworks", () => {
|
||||
const registry = new FrameworkRegistry();
|
||||
registry.register(djangoConfig);
|
||||
const detected = registry.detectFrameworks({
|
||||
"requirements.txt": "django==4.2\ndjango==4.2\n",
|
||||
"pyproject.toml": '[project]\ndependencies = ["django>=4.0"]',
|
||||
});
|
||||
expect(detected).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("createDefault", () => {
|
||||
it("registers all 10 built-in framework configs", () => {
|
||||
const registry = FrameworkRegistry.createDefault();
|
||||
expect(registry.getAllFrameworks()).toHaveLength(10);
|
||||
});
|
||||
|
||||
it("includes frameworks for multiple languages", () => {
|
||||
const registry = FrameworkRegistry.createDefault();
|
||||
expect(registry.getForLanguage("python").length).toBeGreaterThanOrEqual(3);
|
||||
expect(registry.getForLanguage("typescript").length).toBeGreaterThanOrEqual(2);
|
||||
expect(registry.getForLanguage("java").length).toBeGreaterThanOrEqual(1);
|
||||
expect(registry.getForLanguage("ruby").length).toBeGreaterThanOrEqual(1);
|
||||
expect(registry.getForLanguage("go").length).toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
detectLanguageConcepts,
|
||||
} from "../analyzer/language-lesson.js";
|
||||
import type { GraphNode, GraphEdge } from "../types.js";
|
||||
import { typescriptConfig } from "../languages/configs/typescript.js";
|
||||
|
||||
const sampleNode: GraphNode = {
|
||||
id: "func:auth:verifyToken",
|
||||
@@ -51,6 +52,7 @@ describe("language-lesson", () => {
|
||||
sampleNode,
|
||||
sampleEdges,
|
||||
"typescript",
|
||||
typescriptConfig,
|
||||
);
|
||||
expect(prompt).toContain("TypeScript");
|
||||
});
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { LanguageRegistry } from "../languages/language-registry.js";
|
||||
import { typescriptConfig } from "../languages/configs/typescript.js";
|
||||
import { pythonConfig } from "../languages/configs/python.js";
|
||||
|
||||
describe("LanguageRegistry", () => {
|
||||
it("registers and retrieves a language config by id", () => {
|
||||
const registry = new LanguageRegistry();
|
||||
registry.register(typescriptConfig);
|
||||
expect(registry.getById("typescript")).toEqual(typescriptConfig);
|
||||
});
|
||||
|
||||
it("retrieves config by file extension", () => {
|
||||
const registry = new LanguageRegistry();
|
||||
registry.register(typescriptConfig);
|
||||
expect(registry.getByExtension(".ts")?.id).toBe("typescript");
|
||||
expect(registry.getByExtension(".tsx")?.id).toBe("typescript");
|
||||
});
|
||||
|
||||
it("retrieves config for a file path", () => {
|
||||
const registry = new LanguageRegistry();
|
||||
registry.register(typescriptConfig);
|
||||
registry.register(pythonConfig);
|
||||
expect(registry.getForFile("src/index.ts")?.id).toBe("typescript");
|
||||
expect(registry.getForFile("app/models.py")?.id).toBe("python");
|
||||
});
|
||||
|
||||
it("returns null for unknown extensions", () => {
|
||||
const registry = new LanguageRegistry();
|
||||
registry.register(typescriptConfig);
|
||||
expect(registry.getByExtension(".xyz")).toBeNull();
|
||||
expect(registry.getForFile("file.unknown")).toBeNull();
|
||||
});
|
||||
|
||||
it("returns null for files without extensions", () => {
|
||||
const registry = new LanguageRegistry();
|
||||
expect(registry.getForFile("Makefile")).toBeNull();
|
||||
});
|
||||
|
||||
it("lists all registered languages", () => {
|
||||
const registry = new LanguageRegistry();
|
||||
registry.register(typescriptConfig);
|
||||
registry.register(pythonConfig);
|
||||
const all = registry.getAllLanguages();
|
||||
expect(all).toHaveLength(2);
|
||||
expect(all.map(c => c.id)).toContain("typescript");
|
||||
expect(all.map(c => c.id)).toContain("python");
|
||||
});
|
||||
|
||||
describe("createDefault", () => {
|
||||
it("registers all 12 built-in language configs", () => {
|
||||
const registry = LanguageRegistry.createDefault();
|
||||
const all = registry.getAllLanguages();
|
||||
expect(all.length).toBe(12);
|
||||
});
|
||||
|
||||
it("maps all expected extensions", () => {
|
||||
const registry = LanguageRegistry.createDefault();
|
||||
expect(registry.getByExtension(".ts")?.id).toBe("typescript");
|
||||
expect(registry.getByExtension(".py")?.id).toBe("python");
|
||||
expect(registry.getByExtension(".go")?.id).toBe("go");
|
||||
expect(registry.getByExtension(".rs")?.id).toBe("rust");
|
||||
expect(registry.getByExtension(".java")?.id).toBe("java");
|
||||
expect(registry.getByExtension(".rb")?.id).toBe("ruby");
|
||||
expect(registry.getByExtension(".php")?.id).toBe("php");
|
||||
expect(registry.getByExtension(".swift")?.id).toBe("swift");
|
||||
expect(registry.getByExtension(".kt")?.id).toBe("kotlin");
|
||||
expect(registry.getByExtension(".cs")?.id).toBe("csharp");
|
||||
expect(registry.getByExtension(".cpp")?.id).toBe("cpp");
|
||||
expect(registry.getByExtension(".js")?.id).toBe("javascript");
|
||||
});
|
||||
|
||||
it("has no duplicate extension mappings across configs", () => {
|
||||
const registry = LanguageRegistry.createDefault();
|
||||
const all = registry.getAllLanguages();
|
||||
const allExtensions: string[] = [];
|
||||
for (const config of all) {
|
||||
allExtensions.push(...config.extensions);
|
||||
}
|
||||
const unique = new Set(allExtensions);
|
||||
expect(unique.size).toBe(allExtensions.length);
|
||||
});
|
||||
|
||||
it("every config has at least one concept", () => {
|
||||
const registry = LanguageRegistry.createDefault();
|
||||
for (const config of registry.getAllLanguages()) {
|
||||
expect(config.concepts.length).toBeGreaterThan(0);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,11 +1,16 @@
|
||||
import type { GraphNode, GraphEdge } from "../types.js";
|
||||
import type { LanguageConfig } from "../languages/types.js";
|
||||
|
||||
export interface LanguageLessonResult {
|
||||
languageNotes: string;
|
||||
concepts: Array<{ name: string; explanation: string }>;
|
||||
}
|
||||
|
||||
const CONCEPT_PATTERNS: Record<string, string[]> = {
|
||||
/**
|
||||
* Base concept patterns that apply across all languages.
|
||||
* These are merged with language-specific concepts from LanguageConfig.
|
||||
*/
|
||||
const BASE_CONCEPT_PATTERNS: Record<string, string[]> = {
|
||||
"async/await": ["async", "await", "promise", "asynchronous"],
|
||||
"middleware pattern": ["middleware", "interceptor", "pipe"],
|
||||
"generics": ["generic", "type parameter", "template"],
|
||||
@@ -36,12 +41,35 @@ const CONCEPT_PATTERNS: Record<string, string[]> = {
|
||||
"concurrency": ["goroutine", "channel", "thread", "worker", "mutex"],
|
||||
};
|
||||
|
||||
/**
|
||||
* Build the full concept patterns map by merging base patterns with
|
||||
* language-specific concepts from a LanguageConfig (if provided).
|
||||
*/
|
||||
function buildConceptPatterns(
|
||||
langConfig?: LanguageConfig | null,
|
||||
): Record<string, string[]> {
|
||||
const patterns = { ...BASE_CONCEPT_PATTERNS };
|
||||
|
||||
if (langConfig?.concepts) {
|
||||
for (const concept of langConfig.concepts) {
|
||||
if (!patterns[concept]) {
|
||||
// Use the concept name itself as a keyword for detection
|
||||
patterns[concept] = [concept.toLowerCase()];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return patterns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects language concepts present in a graph node based on its tags, summary, and languageNotes.
|
||||
* When a LanguageConfig is provided, language-specific concepts are also detected.
|
||||
*/
|
||||
export function detectLanguageConcepts(
|
||||
node: GraphNode,
|
||||
language: string,
|
||||
langConfig?: LanguageConfig | null,
|
||||
): string[] {
|
||||
const text = [
|
||||
...node.tags,
|
||||
@@ -49,9 +77,10 @@ export function detectLanguageConcepts(
|
||||
node.languageNotes?.toLowerCase() ?? "",
|
||||
].join(" ");
|
||||
|
||||
const patterns = buildConceptPatterns(langConfig);
|
||||
const detected: string[] = [];
|
||||
|
||||
for (const [concept, keywords] of Object.entries(CONCEPT_PATTERNS)) {
|
||||
for (const [concept, keywords] of Object.entries(patterns)) {
|
||||
const found = keywords.some((keyword) =>
|
||||
text.toLowerCase().includes(keyword.toLowerCase()),
|
||||
);
|
||||
@@ -63,11 +92,19 @@ export function detectLanguageConcepts(
|
||||
return detected;
|
||||
}
|
||||
|
||||
const LANGUAGE_DISPLAY_NAMES: Record<string, string> = {
|
||||
typescript: "TypeScript",
|
||||
javascript: "JavaScript",
|
||||
coffeescript: "CoffeeScript",
|
||||
};
|
||||
/**
|
||||
* Get the display name for a language.
|
||||
* Uses LanguageConfig if provided, otherwise falls back to capitalization.
|
||||
*/
|
||||
export function getLanguageDisplayName(
|
||||
language: string,
|
||||
langConfig?: LanguageConfig | null,
|
||||
): string {
|
||||
if (langConfig?.displayName) {
|
||||
return langConfig.displayName;
|
||||
}
|
||||
return language.charAt(0).toUpperCase() + language.slice(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a prompt that asks an LLM to produce a language-specific lesson for a given node.
|
||||
@@ -76,12 +113,11 @@ export function buildLanguageLessonPrompt(
|
||||
node: GraphNode,
|
||||
edges: GraphEdge[],
|
||||
language: string,
|
||||
langConfig?: LanguageConfig | null,
|
||||
): string {
|
||||
const capitalizedLanguage =
|
||||
LANGUAGE_DISPLAY_NAMES[language.toLowerCase()] ??
|
||||
language.charAt(0).toUpperCase() + language.slice(1);
|
||||
const capitalizedLanguage = getLanguageDisplayName(language, langConfig);
|
||||
|
||||
const concepts = detectLanguageConcepts(node, language);
|
||||
const concepts = detectLanguageConcepts(node, language, langConfig);
|
||||
|
||||
const relationships = edges
|
||||
.map((edge) => {
|
||||
|
||||
@@ -36,6 +36,20 @@ export {
|
||||
type LanguageLessonResult,
|
||||
} from "./analyzer/language-lesson.js";
|
||||
export { PluginRegistry } from "./plugins/registry.js";
|
||||
export {
|
||||
LanguageRegistry,
|
||||
FrameworkRegistry,
|
||||
builtinLanguageConfigs,
|
||||
builtinFrameworkConfigs,
|
||||
LanguageConfigSchema,
|
||||
FrameworkConfigSchema,
|
||||
} from "./languages/index.js";
|
||||
export type {
|
||||
LanguageConfig,
|
||||
FrameworkConfig,
|
||||
TreeSitterConfig,
|
||||
FilePatternConfig,
|
||||
} from "./languages/index.js";
|
||||
export {
|
||||
parsePluginConfig,
|
||||
serializePluginConfig,
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import type { LanguageConfig } from "../types.js";
|
||||
|
||||
export const cppConfig = {
|
||||
id: "cpp",
|
||||
displayName: "C/C++",
|
||||
extensions: [".cpp", ".cc", ".cxx", ".c", ".h", ".hpp", ".hxx"],
|
||||
concepts: [
|
||||
"templates",
|
||||
"RAII",
|
||||
"smart pointers",
|
||||
"move semantics",
|
||||
"operator overloading",
|
||||
"virtual functions",
|
||||
"namespaces",
|
||||
"constexpr",
|
||||
"lambda expressions",
|
||||
"STL containers",
|
||||
],
|
||||
filePatterns: {
|
||||
entryPoints: ["main.cpp", "main.c", "src/main.cpp"],
|
||||
barrels: [],
|
||||
tests: ["*_test.cpp", "*_test.cc", "test_*.cpp"],
|
||||
config: ["CMakeLists.txt", "Makefile", "meson.build"],
|
||||
},
|
||||
} satisfies LanguageConfig;
|
||||
@@ -0,0 +1,25 @@
|
||||
import type { LanguageConfig } from "../types.js";
|
||||
|
||||
export const csharpConfig = {
|
||||
id: "csharp",
|
||||
displayName: "C#",
|
||||
extensions: [".cs"],
|
||||
concepts: [
|
||||
"LINQ",
|
||||
"async/await",
|
||||
"generics",
|
||||
"properties",
|
||||
"delegates and events",
|
||||
"attributes",
|
||||
"nullable reference types",
|
||||
"pattern matching",
|
||||
"records",
|
||||
"dependency injection",
|
||||
],
|
||||
filePatterns: {
|
||||
entryPoints: ["Program.cs", "**/Program.cs"],
|
||||
barrels: [],
|
||||
tests: ["*Tests.cs", "*Test.cs"],
|
||||
config: ["*.csproj", "*.sln"],
|
||||
},
|
||||
} satisfies LanguageConfig;
|
||||
@@ -0,0 +1,24 @@
|
||||
import type { LanguageConfig } from "../types.js";
|
||||
|
||||
export const goConfig = {
|
||||
id: "go",
|
||||
displayName: "Go",
|
||||
extensions: [".go"],
|
||||
concepts: [
|
||||
"goroutines",
|
||||
"channels",
|
||||
"interfaces",
|
||||
"struct embedding",
|
||||
"error handling patterns",
|
||||
"defer/panic/recover",
|
||||
"slices",
|
||||
"pointers",
|
||||
"concurrency patterns",
|
||||
],
|
||||
filePatterns: {
|
||||
entryPoints: ["main.go", "cmd/*/main.go"],
|
||||
barrels: [],
|
||||
tests: ["*_test.go"],
|
||||
config: ["go.mod", "go.sum"],
|
||||
},
|
||||
} satisfies LanguageConfig;
|
||||
@@ -0,0 +1,43 @@
|
||||
import type { LanguageConfig } from "../types.js";
|
||||
import { typescriptConfig } from "./typescript.js";
|
||||
import { javascriptConfig } from "./javascript.js";
|
||||
import { pythonConfig } from "./python.js";
|
||||
import { goConfig } from "./go.js";
|
||||
import { rustConfig } from "./rust.js";
|
||||
import { javaConfig } from "./java.js";
|
||||
import { rubyConfig } from "./ruby.js";
|
||||
import { phpConfig } from "./php.js";
|
||||
import { swiftConfig } from "./swift.js";
|
||||
import { kotlinConfig } from "./kotlin.js";
|
||||
import { cppConfig } from "./cpp.js";
|
||||
import { csharpConfig } from "./csharp.js";
|
||||
|
||||
export const builtinLanguageConfigs: LanguageConfig[] = [
|
||||
typescriptConfig,
|
||||
javascriptConfig,
|
||||
pythonConfig,
|
||||
goConfig,
|
||||
rustConfig,
|
||||
javaConfig,
|
||||
rubyConfig,
|
||||
phpConfig,
|
||||
swiftConfig,
|
||||
kotlinConfig,
|
||||
cppConfig,
|
||||
csharpConfig,
|
||||
];
|
||||
|
||||
export {
|
||||
typescriptConfig,
|
||||
javascriptConfig,
|
||||
pythonConfig,
|
||||
goConfig,
|
||||
rustConfig,
|
||||
javaConfig,
|
||||
rubyConfig,
|
||||
phpConfig,
|
||||
swiftConfig,
|
||||
kotlinConfig,
|
||||
cppConfig,
|
||||
csharpConfig,
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
import type { LanguageConfig } from "../types.js";
|
||||
|
||||
export const javaConfig = {
|
||||
id: "java",
|
||||
displayName: "Java",
|
||||
extensions: [".java"],
|
||||
concepts: [
|
||||
"generics",
|
||||
"annotations",
|
||||
"interfaces",
|
||||
"abstract classes",
|
||||
"streams API",
|
||||
"lambdas",
|
||||
"sealed classes",
|
||||
"records",
|
||||
"dependency injection",
|
||||
"checked exceptions",
|
||||
],
|
||||
filePatterns: {
|
||||
entryPoints: [
|
||||
"**/Application.java",
|
||||
"**/Main.java",
|
||||
"src/main/java/**/App.java",
|
||||
],
|
||||
barrels: [],
|
||||
tests: ["*Test.java", "*Tests.java", "*IT.java"],
|
||||
config: ["pom.xml", "build.gradle", "build.gradle.kts"],
|
||||
},
|
||||
} satisfies LanguageConfig;
|
||||
@@ -0,0 +1,43 @@
|
||||
import type { LanguageConfig } from "../types.js";
|
||||
|
||||
export const javascriptConfig = {
|
||||
id: "javascript",
|
||||
displayName: "JavaScript",
|
||||
extensions: [".js", ".jsx", ".mjs", ".cjs"],
|
||||
treeSitter: {
|
||||
wasmPackage: "tree-sitter-javascript",
|
||||
wasmFile: "tree-sitter-javascript.wasm",
|
||||
nodeTypes: {
|
||||
function: [
|
||||
"function_declaration",
|
||||
"arrow_function",
|
||||
"function_expression",
|
||||
"method_definition",
|
||||
],
|
||||
class: ["class_declaration"],
|
||||
import: ["import_statement"],
|
||||
export: ["export_statement"],
|
||||
call: ["call_expression"],
|
||||
string: ["string", "string_fragment"],
|
||||
parameter: ["formal_parameters"],
|
||||
},
|
||||
},
|
||||
concepts: [
|
||||
"closures",
|
||||
"prototypes",
|
||||
"promises",
|
||||
"async/await",
|
||||
"event loop",
|
||||
"destructuring",
|
||||
"spread operator",
|
||||
"proxies",
|
||||
"generators",
|
||||
"modules (ESM/CJS)",
|
||||
],
|
||||
filePatterns: {
|
||||
entryPoints: ["index.js", "src/index.js", "main.js"],
|
||||
barrels: ["index.js"],
|
||||
tests: ["*.test.js", "*.spec.js"],
|
||||
config: ["package.json", "jsconfig.json"],
|
||||
},
|
||||
} satisfies LanguageConfig;
|
||||
@@ -0,0 +1,25 @@
|
||||
import type { LanguageConfig } from "../types.js";
|
||||
|
||||
export const kotlinConfig = {
|
||||
id: "kotlin",
|
||||
displayName: "Kotlin",
|
||||
extensions: [".kt", ".kts"],
|
||||
concepts: [
|
||||
"coroutines",
|
||||
"data classes",
|
||||
"sealed classes",
|
||||
"extension functions",
|
||||
"null safety",
|
||||
"delegation",
|
||||
"DSL builders",
|
||||
"inline functions",
|
||||
"companion objects",
|
||||
"flow",
|
||||
],
|
||||
filePatterns: {
|
||||
entryPoints: ["**/Application.kt", "**/Main.kt"],
|
||||
barrels: [],
|
||||
tests: ["*Test.kt", "*Tests.kt"],
|
||||
config: ["build.gradle.kts", "build.gradle"],
|
||||
},
|
||||
} satisfies LanguageConfig;
|
||||
@@ -0,0 +1,25 @@
|
||||
import type { LanguageConfig } from "../types.js";
|
||||
|
||||
export const phpConfig = {
|
||||
id: "php",
|
||||
displayName: "PHP",
|
||||
extensions: [".php"],
|
||||
concepts: [
|
||||
"namespaces",
|
||||
"traits",
|
||||
"type declarations",
|
||||
"attributes",
|
||||
"enums",
|
||||
"fibers",
|
||||
"closures",
|
||||
"magic methods",
|
||||
"dependency injection",
|
||||
"middleware",
|
||||
],
|
||||
filePatterns: {
|
||||
entryPoints: ["index.php", "public/index.php", "artisan"],
|
||||
barrels: [],
|
||||
tests: ["*Test.php", "tests/**/*.php"],
|
||||
config: ["composer.json", "php.ini"],
|
||||
},
|
||||
} satisfies LanguageConfig;
|
||||
@@ -0,0 +1,40 @@
|
||||
import type { LanguageConfig } from "../types.js";
|
||||
|
||||
export const pythonConfig = {
|
||||
id: "python",
|
||||
displayName: "Python",
|
||||
extensions: [".py", ".pyi"],
|
||||
concepts: [
|
||||
"decorators",
|
||||
"list comprehensions",
|
||||
"generators",
|
||||
"context managers",
|
||||
"type hints",
|
||||
"dunder methods",
|
||||
"metaclasses",
|
||||
"dataclasses",
|
||||
"async/await",
|
||||
"descriptors",
|
||||
"protocols",
|
||||
],
|
||||
filePatterns: {
|
||||
entryPoints: [
|
||||
"main.py",
|
||||
"manage.py",
|
||||
"app.py",
|
||||
"wsgi.py",
|
||||
"asgi.py",
|
||||
"run.py",
|
||||
"__main__.py",
|
||||
],
|
||||
barrels: ["__init__.py"],
|
||||
tests: ["test_*.py", "*_test.py", "conftest.py"],
|
||||
config: [
|
||||
"pyproject.toml",
|
||||
"setup.py",
|
||||
"setup.cfg",
|
||||
"requirements.txt",
|
||||
"Pipfile",
|
||||
],
|
||||
},
|
||||
} satisfies LanguageConfig;
|
||||
@@ -0,0 +1,24 @@
|
||||
import type { LanguageConfig } from "../types.js";
|
||||
|
||||
export const rubyConfig = {
|
||||
id: "ruby",
|
||||
displayName: "Ruby",
|
||||
extensions: [".rb", ".rake"],
|
||||
concepts: [
|
||||
"blocks and procs",
|
||||
"mixins",
|
||||
"metaprogramming",
|
||||
"duck typing",
|
||||
"DSLs",
|
||||
"monkey patching",
|
||||
"symbols",
|
||||
"method_missing",
|
||||
"open classes",
|
||||
],
|
||||
filePatterns: {
|
||||
entryPoints: ["config.ru", "app.rb"],
|
||||
barrels: [],
|
||||
tests: ["*_test.rb", "*_spec.rb", "spec_helper.rb"],
|
||||
config: ["Gemfile", "Rakefile"],
|
||||
},
|
||||
} satisfies LanguageConfig;
|
||||
@@ -0,0 +1,27 @@
|
||||
import type { LanguageConfig } from "../types.js";
|
||||
|
||||
export const rustConfig = {
|
||||
id: "rust",
|
||||
displayName: "Rust",
|
||||
extensions: [".rs"],
|
||||
concepts: [
|
||||
"ownership",
|
||||
"borrowing",
|
||||
"lifetimes",
|
||||
"traits",
|
||||
"pattern matching",
|
||||
"enums with data",
|
||||
"error handling (Result/Option)",
|
||||
"macros",
|
||||
"async/await",
|
||||
"unsafe blocks",
|
||||
"generics",
|
||||
"closures",
|
||||
],
|
||||
filePatterns: {
|
||||
entryPoints: ["src/main.rs", "src/lib.rs"],
|
||||
barrels: ["mod.rs", "lib.rs"],
|
||||
tests: ["tests/*.rs"],
|
||||
config: ["Cargo.toml"],
|
||||
},
|
||||
} satisfies LanguageConfig;
|
||||
@@ -0,0 +1,25 @@
|
||||
import type { LanguageConfig } from "../types.js";
|
||||
|
||||
export const swiftConfig = {
|
||||
id: "swift",
|
||||
displayName: "Swift",
|
||||
extensions: [".swift"],
|
||||
concepts: [
|
||||
"optionals",
|
||||
"protocols",
|
||||
"extensions",
|
||||
"generics",
|
||||
"closures",
|
||||
"property wrappers",
|
||||
"result builders",
|
||||
"actors",
|
||||
"structured concurrency",
|
||||
"value types vs reference types",
|
||||
],
|
||||
filePatterns: {
|
||||
entryPoints: ["Sources/*/main.swift", "App.swift", "AppDelegate.swift"],
|
||||
barrels: [],
|
||||
tests: ["*Tests.swift", "Tests/**/*.swift"],
|
||||
config: ["Package.swift"],
|
||||
},
|
||||
} satisfies LanguageConfig;
|
||||
@@ -0,0 +1,48 @@
|
||||
import type { LanguageConfig } from "../types.js";
|
||||
|
||||
export const typescriptConfig = {
|
||||
id: "typescript",
|
||||
displayName: "TypeScript",
|
||||
extensions: [".ts", ".tsx"],
|
||||
treeSitter: {
|
||||
wasmPackage: "tree-sitter-typescript",
|
||||
wasmFile: "tree-sitter-typescript.wasm",
|
||||
nodeTypes: {
|
||||
function: [
|
||||
"function_declaration",
|
||||
"arrow_function",
|
||||
"function_expression",
|
||||
"method_definition",
|
||||
],
|
||||
class: ["class_declaration"],
|
||||
import: ["import_statement"],
|
||||
export: ["export_statement"],
|
||||
call: ["call_expression"],
|
||||
string: ["string", "string_fragment"],
|
||||
parameter: [
|
||||
"formal_parameters",
|
||||
"required_parameter",
|
||||
"optional_parameter",
|
||||
],
|
||||
},
|
||||
},
|
||||
concepts: [
|
||||
"generics",
|
||||
"type guards",
|
||||
"discriminated unions",
|
||||
"utility types",
|
||||
"decorators",
|
||||
"enums",
|
||||
"interfaces",
|
||||
"type inference",
|
||||
"mapped types",
|
||||
"conditional types",
|
||||
"template literal types",
|
||||
],
|
||||
filePatterns: {
|
||||
entryPoints: ["src/index.ts", "src/main.ts", "src/App.tsx", "index.ts"],
|
||||
barrels: ["index.ts"],
|
||||
tests: ["*.test.ts", "*.spec.ts", "*.test.tsx"],
|
||||
config: ["tsconfig.json"],
|
||||
},
|
||||
} satisfies LanguageConfig;
|
||||
@@ -0,0 +1,80 @@
|
||||
import { FrameworkConfigSchema } from "./types.js";
|
||||
import type { FrameworkConfig } from "./types.js";
|
||||
import { builtinFrameworkConfigs } from "./frameworks/index.js";
|
||||
|
||||
/**
|
||||
* Registry for framework configurations. Provides detection of frameworks
|
||||
* from manifest file contents and lookup by id or language.
|
||||
*/
|
||||
export class FrameworkRegistry {
|
||||
private byId = new Map<string, FrameworkConfig>();
|
||||
private byLanguage = new Map<string, FrameworkConfig[]>();
|
||||
|
||||
register(config: FrameworkConfig): void {
|
||||
const parsed = FrameworkConfigSchema.parse(config);
|
||||
this.byId.set(parsed.id, parsed);
|
||||
|
||||
const existing = this.byLanguage.get(parsed.language) ?? [];
|
||||
existing.push(parsed);
|
||||
this.byLanguage.set(parsed.language, existing);
|
||||
}
|
||||
|
||||
getById(id: string): FrameworkConfig | null {
|
||||
return this.byId.get(id) ?? null;
|
||||
}
|
||||
|
||||
getForLanguage(langId: string): FrameworkConfig[] {
|
||||
return this.byLanguage.get(langId) ?? [];
|
||||
}
|
||||
|
||||
getAllFrameworks(): FrameworkConfig[] {
|
||||
return [...this.byId.values()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect frameworks from manifest file contents.
|
||||
* @param manifests - Map of filename to file content (e.g., { "requirements.txt": "django==4.2\n..." })
|
||||
* @returns Array of detected FrameworkConfig objects
|
||||
*/
|
||||
detectFrameworks(manifests: Record<string, string>): FrameworkConfig[] {
|
||||
const detected = new Set<string>();
|
||||
const results: FrameworkConfig[] = [];
|
||||
|
||||
for (const config of this.byId.values()) {
|
||||
if (detected.has(config.id)) continue;
|
||||
|
||||
for (const manifestFile of config.manifestFiles) {
|
||||
// Match manifest entries by filename (basename match)
|
||||
const content = Object.entries(manifests).find(
|
||||
([key]) => key === manifestFile || key.endsWith(`/${manifestFile}`),
|
||||
)?.[1];
|
||||
|
||||
if (!content) continue;
|
||||
|
||||
const contentLower = content.toLowerCase();
|
||||
const found = config.detectionKeywords.some((keyword) =>
|
||||
contentLower.includes(keyword.toLowerCase()),
|
||||
);
|
||||
|
||||
if (found) {
|
||||
detected.add(config.id);
|
||||
results.push(config);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a registry pre-populated with all built-in framework configs.
|
||||
*/
|
||||
static createDefault(): FrameworkRegistry {
|
||||
const registry = new FrameworkRegistry();
|
||||
for (const config of builtinFrameworkConfigs) {
|
||||
registry.register(config);
|
||||
}
|
||||
return registry;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import type { FrameworkConfig } from "../types.js";
|
||||
|
||||
export const djangoConfig = {
|
||||
id: "django",
|
||||
displayName: "Django",
|
||||
language: "python",
|
||||
detectionKeywords: [
|
||||
"django",
|
||||
"djangorestframework",
|
||||
"django-rest-framework",
|
||||
"django-cors-headers",
|
||||
"django-filter",
|
||||
],
|
||||
manifestFiles: [
|
||||
"requirements.txt",
|
||||
"pyproject.toml",
|
||||
"setup.py",
|
||||
"setup.cfg",
|
||||
"Pipfile",
|
||||
],
|
||||
promptSnippetPath: "./frameworks/django.md",
|
||||
entryPoints: ["manage.py", "wsgi.py", "asgi.py"],
|
||||
layerHints: {
|
||||
views: "api",
|
||||
models: "data",
|
||||
serializers: "api",
|
||||
urls: "api",
|
||||
templates: "ui",
|
||||
migrations: "data",
|
||||
management: "config",
|
||||
signals: "service",
|
||||
admin: "config",
|
||||
forms: "ui",
|
||||
templatetags: "utility",
|
||||
},
|
||||
} satisfies FrameworkConfig;
|
||||
@@ -0,0 +1,26 @@
|
||||
import type { FrameworkConfig } from "../types.js";
|
||||
|
||||
export const expressConfig = {
|
||||
id: "express",
|
||||
displayName: "Express",
|
||||
language: "javascript",
|
||||
detectionKeywords: ["express", "express-validator", "cors", "body-parser"],
|
||||
manifestFiles: ["package.json"],
|
||||
promptSnippetPath: "./frameworks/express.md",
|
||||
entryPoints: [
|
||||
"src/index.js",
|
||||
"src/app.js",
|
||||
"server.js",
|
||||
"app.js",
|
||||
"src/index.ts",
|
||||
"src/app.ts",
|
||||
],
|
||||
layerHints: {
|
||||
routes: "api",
|
||||
controllers: "service",
|
||||
models: "data",
|
||||
middleware: "middleware",
|
||||
services: "service",
|
||||
db: "data",
|
||||
},
|
||||
} satisfies FrameworkConfig;
|
||||
@@ -0,0 +1,25 @@
|
||||
import type { FrameworkConfig } from "../types.js";
|
||||
|
||||
export const fastapiConfig = {
|
||||
id: "fastapi",
|
||||
displayName: "FastAPI",
|
||||
language: "python",
|
||||
detectionKeywords: ["fastapi", "uvicorn", "starlette"],
|
||||
manifestFiles: [
|
||||
"requirements.txt",
|
||||
"pyproject.toml",
|
||||
"setup.py",
|
||||
"setup.cfg",
|
||||
"Pipfile",
|
||||
],
|
||||
promptSnippetPath: "./frameworks/fastapi.md",
|
||||
entryPoints: ["main.py", "app.py"],
|
||||
layerHints: {
|
||||
routers: "api",
|
||||
schemas: "types",
|
||||
models: "data",
|
||||
dependencies: "service",
|
||||
crud: "service",
|
||||
api: "api",
|
||||
},
|
||||
} satisfies FrameworkConfig;
|
||||
@@ -0,0 +1,31 @@
|
||||
import type { FrameworkConfig } from "../types.js";
|
||||
|
||||
export const flaskConfig = {
|
||||
id: "flask",
|
||||
displayName: "Flask",
|
||||
language: "python",
|
||||
detectionKeywords: [
|
||||
"flask",
|
||||
"flask-restful",
|
||||
"flask-sqlalchemy",
|
||||
"flask-marshmallow",
|
||||
"flask-wtf",
|
||||
],
|
||||
manifestFiles: [
|
||||
"requirements.txt",
|
||||
"pyproject.toml",
|
||||
"setup.py",
|
||||
"setup.cfg",
|
||||
"Pipfile",
|
||||
],
|
||||
promptSnippetPath: "./frameworks/flask.md",
|
||||
entryPoints: ["app.py", "run.py", "wsgi.py"],
|
||||
layerHints: {
|
||||
blueprints: "api",
|
||||
views: "api",
|
||||
models: "data",
|
||||
forms: "ui",
|
||||
templates: "ui",
|
||||
extensions: "config",
|
||||
},
|
||||
} satisfies FrameworkConfig;
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { FrameworkConfig } from "../types.js";
|
||||
|
||||
export const ginConfig = {
|
||||
id: "gin",
|
||||
displayName: "Gin",
|
||||
language: "go",
|
||||
detectionKeywords: ["github.com/gin-gonic/gin"],
|
||||
manifestFiles: ["go.mod"],
|
||||
promptSnippetPath: "./frameworks/gin.md",
|
||||
entryPoints: ["main.go", "cmd/server/main.go"],
|
||||
layerHints: {
|
||||
handlers: "api",
|
||||
routes: "api",
|
||||
models: "data",
|
||||
middleware: "middleware",
|
||||
services: "service",
|
||||
repository: "data",
|
||||
},
|
||||
} satisfies FrameworkConfig;
|
||||
@@ -0,0 +1,38 @@
|
||||
import type { FrameworkConfig } from "../types.js";
|
||||
|
||||
import { djangoConfig } from "./django.js";
|
||||
import { fastapiConfig } from "./fastapi.js";
|
||||
import { flaskConfig } from "./flask.js";
|
||||
import { reactConfig } from "./react.js";
|
||||
import { nextjsConfig } from "./nextjs.js";
|
||||
import { expressConfig } from "./express.js";
|
||||
import { vueConfig } from "./vue.js";
|
||||
import { springConfig } from "./spring.js";
|
||||
import { railsConfig } from "./rails.js";
|
||||
import { ginConfig } from "./gin.js";
|
||||
|
||||
export const builtinFrameworkConfigs: FrameworkConfig[] = [
|
||||
djangoConfig,
|
||||
fastapiConfig,
|
||||
flaskConfig,
|
||||
reactConfig,
|
||||
nextjsConfig,
|
||||
expressConfig,
|
||||
vueConfig,
|
||||
springConfig,
|
||||
railsConfig,
|
||||
ginConfig,
|
||||
];
|
||||
|
||||
export {
|
||||
djangoConfig,
|
||||
fastapiConfig,
|
||||
flaskConfig,
|
||||
reactConfig,
|
||||
nextjsConfig,
|
||||
expressConfig,
|
||||
vueConfig,
|
||||
springConfig,
|
||||
railsConfig,
|
||||
ginConfig,
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
import type { FrameworkConfig } from "../types.js";
|
||||
|
||||
export const nextjsConfig = {
|
||||
id: "nextjs",
|
||||
displayName: "Next.js",
|
||||
language: "typescript",
|
||||
detectionKeywords: ["next", "@next/font", "@next/image"],
|
||||
manifestFiles: ["package.json"],
|
||||
promptSnippetPath: "./frameworks/nextjs.md",
|
||||
entryPoints: [
|
||||
"src/app/layout.tsx",
|
||||
"pages/_app.tsx",
|
||||
"src/pages/_app.tsx",
|
||||
],
|
||||
layerHints: {
|
||||
app: "ui",
|
||||
pages: "ui",
|
||||
api: "api",
|
||||
components: "ui",
|
||||
lib: "service",
|
||||
middleware: "middleware",
|
||||
},
|
||||
} satisfies FrameworkConfig;
|
||||
@@ -0,0 +1,28 @@
|
||||
import type { FrameworkConfig } from "../types.js";
|
||||
|
||||
export const railsConfig = {
|
||||
id: "rails",
|
||||
displayName: "Ruby on Rails",
|
||||
language: "ruby",
|
||||
detectionKeywords: [
|
||||
"rails",
|
||||
"railties",
|
||||
"actionpack",
|
||||
"activerecord",
|
||||
"actionview",
|
||||
],
|
||||
manifestFiles: ["Gemfile"],
|
||||
promptSnippetPath: "./frameworks/rails.md",
|
||||
entryPoints: ["config.ru", "bin/rails"],
|
||||
layerHints: {
|
||||
controllers: "api",
|
||||
models: "data",
|
||||
views: "ui",
|
||||
helpers: "utility",
|
||||
mailers: "service",
|
||||
jobs: "service",
|
||||
channels: "service",
|
||||
middleware: "middleware",
|
||||
lib: "service",
|
||||
},
|
||||
} satisfies FrameworkConfig;
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { FrameworkConfig } from "../types.js";
|
||||
|
||||
export const reactConfig = {
|
||||
id: "react",
|
||||
displayName: "React",
|
||||
language: "typescript",
|
||||
detectionKeywords: ["react", "react-dom", "@types/react"],
|
||||
manifestFiles: ["package.json"],
|
||||
promptSnippetPath: "./frameworks/react.md",
|
||||
entryPoints: ["src/App.tsx", "src/App.jsx", "src/index.tsx", "src/main.tsx"],
|
||||
layerHints: {
|
||||
components: "ui",
|
||||
hooks: "service",
|
||||
pages: "ui",
|
||||
contexts: "service",
|
||||
utils: "utility",
|
||||
lib: "service",
|
||||
},
|
||||
} satisfies FrameworkConfig;
|
||||
@@ -0,0 +1,27 @@
|
||||
import type { FrameworkConfig } from "../types.js";
|
||||
|
||||
export const springConfig = {
|
||||
id: "spring",
|
||||
displayName: "Spring Boot",
|
||||
language: "java",
|
||||
detectionKeywords: [
|
||||
"spring-boot",
|
||||
"spring-boot-starter",
|
||||
"spring-web",
|
||||
"spring-data",
|
||||
"org.springframework",
|
||||
],
|
||||
manifestFiles: ["pom.xml", "build.gradle", "build.gradle.kts"],
|
||||
promptSnippetPath: "./frameworks/spring.md",
|
||||
entryPoints: ["**/Application.java", "**/App.java"],
|
||||
layerHints: {
|
||||
controller: "api",
|
||||
service: "service",
|
||||
repository: "data",
|
||||
model: "data",
|
||||
entity: "data",
|
||||
config: "config",
|
||||
dto: "types",
|
||||
security: "middleware",
|
||||
},
|
||||
} satisfies FrameworkConfig;
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { FrameworkConfig } from "../types.js";
|
||||
|
||||
export const vueConfig = {
|
||||
id: "vue",
|
||||
displayName: "Vue",
|
||||
language: "typescript",
|
||||
detectionKeywords: ["vue", "@vue/cli-service", "nuxt", "vite-plugin-vue"],
|
||||
manifestFiles: ["package.json"],
|
||||
promptSnippetPath: "./frameworks/vue.md",
|
||||
entryPoints: ["src/main.ts", "src/App.vue", "src/main.js"],
|
||||
layerHints: {
|
||||
components: "ui",
|
||||
views: "ui",
|
||||
store: "service",
|
||||
composables: "service",
|
||||
router: "config",
|
||||
plugins: "config",
|
||||
},
|
||||
} satisfies FrameworkConfig;
|
||||
@@ -0,0 +1,22 @@
|
||||
// Types
|
||||
export type {
|
||||
LanguageConfig,
|
||||
TreeSitterConfig,
|
||||
FilePatternConfig,
|
||||
FrameworkConfig,
|
||||
} from "./types.js";
|
||||
|
||||
export {
|
||||
LanguageConfigSchema,
|
||||
TreeSitterConfigSchema,
|
||||
FilePatternConfigSchema,
|
||||
FrameworkConfigSchema,
|
||||
} from "./types.js";
|
||||
|
||||
// Registries
|
||||
export { LanguageRegistry } from "./language-registry.js";
|
||||
export { FrameworkRegistry } from "./framework-registry.js";
|
||||
|
||||
// Built-in configs
|
||||
export { builtinLanguageConfigs } from "./configs/index.js";
|
||||
export { builtinFrameworkConfigs } from "./frameworks/index.js";
|
||||
@@ -0,0 +1,53 @@
|
||||
import { LanguageConfigSchema } from "./types.js";
|
||||
import type { LanguageConfig } from "./types.js";
|
||||
import { builtinLanguageConfigs } from "./configs/index.js";
|
||||
|
||||
/**
|
||||
* Registry for language configurations. Maps language ids and file extensions
|
||||
* to their corresponding LanguageConfig objects.
|
||||
*/
|
||||
export class LanguageRegistry {
|
||||
private byId = new Map<string, LanguageConfig>();
|
||||
private byExtension = new Map<string, LanguageConfig>();
|
||||
|
||||
register(config: LanguageConfig): void {
|
||||
const parsed = LanguageConfigSchema.parse(config);
|
||||
this.byId.set(parsed.id, parsed);
|
||||
for (const ext of parsed.extensions) {
|
||||
// Normalize: strip leading dot if present for lookup consistency
|
||||
const key = ext.startsWith(".") ? ext : `.${ext}`;
|
||||
this.byExtension.set(key, parsed);
|
||||
}
|
||||
}
|
||||
|
||||
getById(id: string): LanguageConfig | null {
|
||||
return this.byId.get(id) ?? null;
|
||||
}
|
||||
|
||||
getByExtension(ext: string): LanguageConfig | null {
|
||||
const key = ext.startsWith(".") ? ext : `.${ext}`;
|
||||
return this.byExtension.get(key) ?? null;
|
||||
}
|
||||
|
||||
getForFile(filePath: string): LanguageConfig | null {
|
||||
const lastDot = filePath.lastIndexOf(".");
|
||||
if (lastDot === -1) return null;
|
||||
const ext = filePath.slice(lastDot).toLowerCase();
|
||||
return this.getByExtension(ext);
|
||||
}
|
||||
|
||||
getAllLanguages(): LanguageConfig[] {
|
||||
return [...this.byId.values()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a registry pre-populated with all built-in language configs.
|
||||
*/
|
||||
static createDefault(): LanguageRegistry {
|
||||
const registry = new LanguageRegistry();
|
||||
for (const config of builtinLanguageConfigs) {
|
||||
registry.register(config);
|
||||
}
|
||||
return registry;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import { z } from "zod";
|
||||
|
||||
// Tree-sitter node type mappings for a language
|
||||
export const TreeSitterConfigSchema = z.object({
|
||||
wasmPackage: z.string(),
|
||||
wasmFile: z.string(),
|
||||
nodeTypes: z.object({
|
||||
function: z.array(z.string()),
|
||||
class: z.array(z.string()),
|
||||
import: z.array(z.string()),
|
||||
export: z.array(z.string()),
|
||||
call: z.array(z.string()),
|
||||
string: z.array(z.string()),
|
||||
parameter: z.array(z.string()),
|
||||
}),
|
||||
});
|
||||
|
||||
export type TreeSitterConfig = z.infer<typeof TreeSitterConfigSchema>;
|
||||
|
||||
// File pattern conventions for a language
|
||||
export const FilePatternConfigSchema = z.object({
|
||||
entryPoints: z.array(z.string()),
|
||||
barrels: z.array(z.string()),
|
||||
tests: z.array(z.string()),
|
||||
config: z.array(z.string()),
|
||||
});
|
||||
|
||||
export type FilePatternConfig = z.infer<typeof FilePatternConfigSchema>;
|
||||
|
||||
// Complete language configuration
|
||||
export const LanguageConfigSchema = z.object({
|
||||
id: z.string().min(1),
|
||||
displayName: z.string().min(1),
|
||||
extensions: z.array(z.string()).min(1),
|
||||
treeSitter: TreeSitterConfigSchema.optional(),
|
||||
concepts: z.array(z.string()),
|
||||
filePatterns: FilePatternConfigSchema,
|
||||
});
|
||||
|
||||
export type LanguageConfig = z.infer<typeof LanguageConfigSchema>;
|
||||
|
||||
// Framework configuration
|
||||
export const FrameworkConfigSchema = z.object({
|
||||
id: z.string().min(1),
|
||||
displayName: z.string().min(1),
|
||||
language: z.string().min(1),
|
||||
detectionKeywords: z.array(z.string()).min(1),
|
||||
manifestFiles: z.array(z.string()).min(1),
|
||||
promptSnippetPath: z.string().min(1),
|
||||
entryPoints: z.array(z.string()).optional(),
|
||||
layerHints: z.record(z.string(), z.string()).optional(),
|
||||
});
|
||||
|
||||
export type FrameworkConfig = z.infer<typeof FrameworkConfigSchema>;
|
||||
@@ -1,30 +1,21 @@
|
||||
import type { AnalyzerPlugin, StructuralAnalysis, ImportResolution } from "../types.js";
|
||||
|
||||
const EXTENSION_TO_LANGUAGE: Record<string, string> = {
|
||||
ts: "typescript",
|
||||
tsx: "typescript",
|
||||
js: "javascript",
|
||||
jsx: "javascript",
|
||||
py: "python",
|
||||
go: "go",
|
||||
rs: "rust",
|
||||
rb: "ruby",
|
||||
java: "java",
|
||||
kt: "kotlin",
|
||||
cs: "csharp",
|
||||
cpp: "cpp",
|
||||
c: "c",
|
||||
swift: "swift",
|
||||
php: "php",
|
||||
};
|
||||
import { LanguageRegistry } from "../languages/language-registry.js";
|
||||
|
||||
/**
|
||||
* Registry for analyzer plugins. Maps languages to plugins and provides
|
||||
* a unified interface for analyzing files across languages.
|
||||
*
|
||||
* Uses LanguageRegistry for extension-to-language mapping instead of
|
||||
* a hardcoded lookup table.
|
||||
*/
|
||||
export class PluginRegistry {
|
||||
private plugins: AnalyzerPlugin[] = [];
|
||||
private languageMap = new Map<string, AnalyzerPlugin>();
|
||||
private languageRegistry: LanguageRegistry;
|
||||
|
||||
constructor(languageRegistry?: LanguageRegistry) {
|
||||
this.languageRegistry = languageRegistry ?? LanguageRegistry.createDefault();
|
||||
}
|
||||
|
||||
register(plugin: AnalyzerPlugin): void {
|
||||
this.plugins.push(plugin);
|
||||
@@ -50,11 +41,16 @@ export class PluginRegistry {
|
||||
}
|
||||
|
||||
getPluginForFile(filePath: string): AnalyzerPlugin | null {
|
||||
const ext = filePath.split(".").pop()?.toLowerCase();
|
||||
if (!ext) return null;
|
||||
const language = EXTENSION_TO_LANGUAGE[ext];
|
||||
if (!language) return null;
|
||||
return this.getPluginForLanguage(language);
|
||||
const langConfig = this.languageRegistry.getForFile(filePath);
|
||||
if (!langConfig) return null;
|
||||
return this.getPluginForLanguage(langConfig.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the language id for a file path using the language registry.
|
||||
*/
|
||||
getLanguageForFile(filePath: string): string | null {
|
||||
return this.languageRegistry.getForFile(filePath)?.id ?? null;
|
||||
}
|
||||
|
||||
analyzeFile(filePath: string, content: string): StructuralAnalysis | null {
|
||||
|
||||
@@ -6,6 +6,7 @@ import type {
|
||||
ImportResolution,
|
||||
CallGraphEntry,
|
||||
} from "../types.js";
|
||||
import type { LanguageConfig } from "../languages/types.js";
|
||||
|
||||
// web-tree-sitter uses CJS internally; we need createRequire for .wasm resolution
|
||||
const require = createRequire(import.meta.url);
|
||||
@@ -14,23 +15,6 @@ type TreeSitterParser = import("web-tree-sitter").Parser;
|
||||
type TreeSitterLanguage = import("web-tree-sitter").Language;
|
||||
type TreeSitterNode = import("web-tree-sitter").Node;
|
||||
|
||||
function languageKeyFromPath(filePath: string): string {
|
||||
const ext = extname(filePath).toLowerCase();
|
||||
switch (ext) {
|
||||
case ".ts":
|
||||
return "typescript";
|
||||
case ".tsx":
|
||||
return "tsx";
|
||||
case ".js":
|
||||
case ".mjs":
|
||||
case ".cjs":
|
||||
case ".jsx":
|
||||
return "javascript";
|
||||
default:
|
||||
throw new Error(`Unsupported file extension: ${ext}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively traverse an AST tree, calling the visitor for each node.
|
||||
*/
|
||||
@@ -155,17 +139,81 @@ function extractImportSpecifiers(
|
||||
return specifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Config-driven tree-sitter plugin.
|
||||
*
|
||||
* Accepts LanguageConfig objects to determine which languages to support
|
||||
* and how to load their WASM grammars. Currently provides deep structural
|
||||
* analysis for TypeScript/JavaScript; other languages with tree-sitter configs
|
||||
* get basic function/class/import extraction.
|
||||
*
|
||||
* Languages without tree-sitter configs are gracefully skipped (the LLM
|
||||
* agent handles analysis for those).
|
||||
*/
|
||||
export class TreeSitterPlugin implements AnalyzerPlugin {
|
||||
readonly name = "tree-sitter";
|
||||
readonly languages = ["typescript", "javascript"];
|
||||
readonly languages: string[];
|
||||
|
||||
private configs: LanguageConfig[];
|
||||
|
||||
// Pre-loaded parser constructor and languages (set by init())
|
||||
private _ParserClass:
|
||||
| (new () => TreeSitterParser)
|
||||
| null = null;
|
||||
private _languages = new Map<string, TreeSitterLanguage>();
|
||||
private _extensionToLang = new Map<string, string>();
|
||||
private _initialized = false;
|
||||
|
||||
/**
|
||||
* Create a TreeSitterPlugin with the given language configs.
|
||||
* Only configs that have a `treeSitter` field will be loaded.
|
||||
* If no configs are provided, defaults to TypeScript and JavaScript.
|
||||
*/
|
||||
constructor(configs?: LanguageConfig[]) {
|
||||
if (configs) {
|
||||
this.configs = configs.filter((c) => c.treeSitter);
|
||||
} else {
|
||||
// Default: TS/JS for backward compatibility
|
||||
this.configs = [];
|
||||
}
|
||||
|
||||
// Derive supported languages and extension map from configs
|
||||
const langs: string[] = [];
|
||||
for (const config of this.configs) {
|
||||
langs.push(config.id);
|
||||
for (const ext of config.extensions) {
|
||||
const key = ext.startsWith(".") ? ext : `.${ext}`;
|
||||
this._extensionToLang.set(key, config.id);
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback for backward compat when no configs provided
|
||||
if (langs.length === 0) {
|
||||
langs.push("typescript", "javascript");
|
||||
this._extensionToLang.set(".ts", "typescript");
|
||||
this._extensionToLang.set(".tsx", "typescript");
|
||||
this._extensionToLang.set(".js", "javascript");
|
||||
this._extensionToLang.set(".mjs", "javascript");
|
||||
this._extensionToLang.set(".cjs", "javascript");
|
||||
this._extensionToLang.set(".jsx", "javascript");
|
||||
}
|
||||
|
||||
this.languages = langs;
|
||||
}
|
||||
|
||||
private languageKeyFromPath(filePath: string): string {
|
||||
const ext = extname(filePath).toLowerCase();
|
||||
|
||||
// Special case: .tsx needs its own grammar
|
||||
if (ext === ".tsx") return "tsx";
|
||||
|
||||
const lang = this._extensionToLang.get(ext);
|
||||
if (!lang) {
|
||||
throw new Error(`Unsupported file extension: ${ext}`);
|
||||
}
|
||||
return lang;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the plugin by loading the WASM module and all language grammars.
|
||||
* Must be called (and awaited) before any synchronous methods.
|
||||
@@ -180,26 +228,68 @@ export class TreeSitterPlugin implements AnalyzerPlugin {
|
||||
await ParserCls.init();
|
||||
this._ParserClass = ParserCls as unknown as new () => TreeSitterParser;
|
||||
|
||||
// Pre-load all supported language grammars
|
||||
const tsWasm = require.resolve(
|
||||
"tree-sitter-typescript/tree-sitter-typescript.wasm",
|
||||
);
|
||||
const tsxWasm = require.resolve(
|
||||
"tree-sitter-typescript/tree-sitter-tsx.wasm",
|
||||
);
|
||||
const jsWasm = require.resolve(
|
||||
"tree-sitter-javascript/tree-sitter-javascript.wasm",
|
||||
);
|
||||
if (this.configs.length > 0) {
|
||||
// Load grammars from configs
|
||||
const loadPromises: Promise<void>[] = [];
|
||||
|
||||
const [tsLang, tsxLang, jsLang] = await Promise.all([
|
||||
LanguageCls.load(tsWasm),
|
||||
LanguageCls.load(tsxWasm),
|
||||
LanguageCls.load(jsWasm),
|
||||
]);
|
||||
for (const config of this.configs) {
|
||||
if (!config.treeSitter) continue;
|
||||
|
||||
const loadGrammar = async () => {
|
||||
try {
|
||||
const wasmPath = require.resolve(
|
||||
`${config.treeSitter!.wasmPackage}/${config.treeSitter!.wasmFile}`,
|
||||
);
|
||||
const lang = await LanguageCls.load(wasmPath);
|
||||
this._languages.set(config.id, lang);
|
||||
|
||||
// Special handling for TypeScript: also load TSX grammar
|
||||
if (config.id === "typescript") {
|
||||
try {
|
||||
const tsxWasm = require.resolve(
|
||||
`${config.treeSitter!.wasmPackage}/tree-sitter-tsx.wasm`,
|
||||
);
|
||||
const tsxLang = await LanguageCls.load(tsxWasm);
|
||||
this._languages.set("tsx", tsxLang);
|
||||
} catch {
|
||||
// TSX grammar not available; .tsx files will fall back to TS grammar
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Grammar not available — this language will be skipped gracefully
|
||||
console.debug?.(
|
||||
`tree-sitter: Could not load grammar for ${config.id}, skipping structural analysis`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
loadPromises.push(loadGrammar());
|
||||
}
|
||||
|
||||
await Promise.all(loadPromises);
|
||||
} else {
|
||||
// Legacy fallback: load TS/JS grammars directly
|
||||
const tsWasm = require.resolve(
|
||||
"tree-sitter-typescript/tree-sitter-typescript.wasm",
|
||||
);
|
||||
const tsxWasm = require.resolve(
|
||||
"tree-sitter-typescript/tree-sitter-tsx.wasm",
|
||||
);
|
||||
const jsWasm = require.resolve(
|
||||
"tree-sitter-javascript/tree-sitter-javascript.wasm",
|
||||
);
|
||||
|
||||
const [tsLang, tsxLang, jsLang] = await Promise.all([
|
||||
LanguageCls.load(tsWasm),
|
||||
LanguageCls.load(tsxWasm),
|
||||
LanguageCls.load(jsWasm),
|
||||
]);
|
||||
|
||||
this._languages.set("typescript", tsLang);
|
||||
this._languages.set("tsx", tsxLang);
|
||||
this._languages.set("javascript", jsLang);
|
||||
}
|
||||
|
||||
this._languages.set("typescript", tsLang);
|
||||
this._languages.set("tsx", tsxLang);
|
||||
this._languages.set("javascript", jsLang);
|
||||
this._initialized = true;
|
||||
}
|
||||
|
||||
@@ -207,16 +297,17 @@ export class TreeSitterPlugin implements AnalyzerPlugin {
|
||||
* Create a parser set to the appropriate language for the given file.
|
||||
* This is synchronous because all languages are pre-loaded during init().
|
||||
*/
|
||||
private getParser(filePath: string): TreeSitterParser {
|
||||
private getParser(filePath: string): TreeSitterParser | null {
|
||||
if (!this._initialized || !this._ParserClass) {
|
||||
throw new Error(
|
||||
"TreeSitterPlugin.init() must be called before use",
|
||||
);
|
||||
}
|
||||
const langKey = languageKeyFromPath(filePath);
|
||||
const langKey = this.languageKeyFromPath(filePath);
|
||||
const lang = this._languages.get(langKey);
|
||||
if (!lang) {
|
||||
throw new Error(`Language not loaded: ${langKey}`);
|
||||
// Language grammar not loaded — graceful degradation
|
||||
return null;
|
||||
}
|
||||
const parser = new this._ParserClass();
|
||||
parser.setLanguage(lang);
|
||||
@@ -228,6 +319,10 @@ export class TreeSitterPlugin implements AnalyzerPlugin {
|
||||
content: string,
|
||||
): StructuralAnalysis {
|
||||
const parser = this.getParser(filePath);
|
||||
if (!parser) {
|
||||
return { functions: [], classes: [], imports: [], exports: [] };
|
||||
}
|
||||
|
||||
const tree = parser.parse(content);
|
||||
if (!tree) {
|
||||
parser.delete();
|
||||
@@ -290,6 +385,8 @@ export class TreeSitterPlugin implements AnalyzerPlugin {
|
||||
content: string,
|
||||
): CallGraphEntry[] {
|
||||
const parser = this.getParser(filePath);
|
||||
if (!parser) return [];
|
||||
|
||||
const tree = parser.parse(content);
|
||||
if (!tree) {
|
||||
parser.delete();
|
||||
|
||||
@@ -1,208 +0,0 @@
|
||||
# Python Codebase Support — Change Review Guide
|
||||
|
||||
This document explains every change made to add Python and Python framework support. It is written for a reviewer who wants to verify correctness, spot regressions, and understand the rationale for each decision.
|
||||
|
||||
---
|
||||
|
||||
## Background: What Was Wrong
|
||||
|
||||
The tool worked well for TypeScript/JavaScript codebases. For Python codebases it would:
|
||||
- Fail to detect frameworks (Django, FastAPI, Flask) — `frameworks: []` always
|
||||
- Miss common Python entry points (`manage.py`, `app.py`, `wsgi.py`) — defaulting to no entry point
|
||||
- Score Python entry points much lower than TS equivalents in the tour builder (4 Python patterns vs 8 JS/TS patterns)
|
||||
- Miss Python's `__init__.py` as a barrel/entry-point equivalent (only `index.ts`/`index.js` were recognized)
|
||||
- Have no layer guidance for FastAPI or Flask (only Django had a brief mention)
|
||||
- Ignore `pyproject.toml` for project name extraction
|
||||
|
||||
The bias was **only in agent prompts** (markdown files). The graph schema, dashboard, search engine, and core plugin architecture are language-agnostic and required no changes.
|
||||
|
||||
---
|
||||
|
||||
## Files Changed
|
||||
|
||||
### 1. `project-scanner-prompt.md`
|
||||
|
||||
**What changed:**
|
||||
|
||||
**Step 5 (Framework Detection)** — Extended the Python manifest reading from "confirms Python project" to actually detecting frameworks:
|
||||
- `requirements.txt`: now reads line-by-line, strips version specifiers, and matches against a Python framework keyword list: `django`, `djangorestframework`, `fastapi`, `flask`, `sqlalchemy`, `alembic`, `celery`, `pydantic`, `uvicorn`, `gunicorn`, `aiohttp`, `tornado`, `starlette`, `pytest`, `hypothesis`, `channels`
|
||||
- `pyproject.toml`: now parses `[project].dependencies` and `[tool.poetry.dependencies]`, applies the same keyword matching, and also checks for `[tool.pytest.ini_options]` (pytest) and `[tool.django]` (Django)
|
||||
- `setup.py`, `setup.cfg`, `Pipfile`: now apply the same Python framework keyword matching
|
||||
|
||||
**Step 7 (Project Name)** — Added `pyproject.toml` to the priority order between `go.mod` and directory name. Checks `[project].name` first, then `[tool.poetry].name`.
|
||||
|
||||
**Why:** Without framework detection, `frameworks: []` is passed to every downstream agent. The framework-specific guidance injected in Phase 2 and Phase 4 of SKILL.md is only useful when `frameworks` is non-empty.
|
||||
|
||||
**Regression risk:** None. The JS framework detection in `package.json` is unchanged. The Python additions are additive.
|
||||
|
||||
**How to verify:** Run `/understand` on a Django project with `requirements.txt` containing `django`. Check that `scan-result.json` has `frameworks: ["Django"]`.
|
||||
|
||||
---
|
||||
|
||||
### 2. `SKILL.md`
|
||||
|
||||
**What changed:**
|
||||
|
||||
**Phase 0 (entry point detection, line 57)** — Added Python entry points to the pattern list:
|
||||
- Before: `src/index.ts`, `src/main.ts`, `src/App.tsx`, `main.py`, `main.go`, `src/main.rs`, `index.js`
|
||||
- After: added `manage.py`, `app.py`, `wsgi.py`, `asgi.py`, `run.py`, `__main__.py`
|
||||
|
||||
**Why:** A Django project's real entry point is `manage.py`. A FastAPI/Flask project uses `app.py` or `run.py`. Without these, `$ENTRY_POINT` is empty for most Python projects, and the tour builder gets no starting hint.
|
||||
|
||||
**Phase 2 (file-analyzer framework guidance)** — Extended the inline framework hints:
|
||||
- Django: added `serializers.py`, `signals.py`, `admin.py`, `migrations/` descriptions
|
||||
- Added FastAPI: describes `@router` decorator files, Pydantic schemas, `Depends()` providers
|
||||
- Added Flask: describes `@blueprint.route`, `blueprints/`, SQLAlchemy `models.py`
|
||||
- Added addendum injection: if `Django` detected, reads `./django-analyzer-addendum.md` and appends to the file-analyzer prompt. If `FastAPI` or `Flask` detected, reads `./fastapi-analyzer-addendum.md` and appends.
|
||||
|
||||
**Phase 4 (architecture-analyzer framework hints)** — Extended the inline layer hints:
|
||||
- Django: added `serializers.py`, `signals.py`, `migrations/` → specific layers
|
||||
- Added FastAPI: router files → API, Pydantic schemas → Types, `dependencies.py` → Service, DB files → Data
|
||||
- Added Flask: blueprint route files → API, `models.py` → Data, `forms.py` → UI, `extensions.py` → Config
|
||||
- Added addendum injection: same logic as Phase 2
|
||||
|
||||
**Regression risk:** Low. The addendum injection only triggers when those frameworks are in the detected list. The inline guidance additions are additive strings — they don't change the structure of the injected context.
|
||||
|
||||
**How to verify:**
|
||||
- Run on a FastAPI project: check `layers.json` has a `layer:types` or `layer:api` with Pydantic schema files assigned correctly
|
||||
- Run on a TS project: check that no Django/FastAPI addendum content appears in the analysis (it shouldn't, since `frameworks` won't contain those values)
|
||||
|
||||
---
|
||||
|
||||
### 3. `architecture-analyzer-prompt.md`
|
||||
|
||||
**What changed:**
|
||||
|
||||
**Directory pattern table** — Added Python-specific directory names:
|
||||
|
||||
| Added | Pattern Label | Why |
|
||||
|-------|---------------|-----|
|
||||
| `migrations` | `data` | Django/Alembic migration directories hold schema history — Data Layer |
|
||||
| `management`, `commands` | `config` | Django management command directories |
|
||||
| `templatetags` | `utility` | Django custom template tag directories |
|
||||
| `signals` | `service` | Signal handler modules — cross-cutting service logic |
|
||||
| `serializers` | `api` | DRF serializer directories |
|
||||
|
||||
**File-level pattern matching** — Three changes:
|
||||
1. Added `test_*.py` to the test pattern (Python's `pytest` naming convention)
|
||||
2. Added `__init__.py` at a directory root → `entry` pattern (Python package barrel equivalent of `index.ts`)
|
||||
3. Added `manage.py` → `entry` and `wsgi.py`/`asgi.py` → `config`
|
||||
4. Clarified `*.d.ts → types` with "(TypeScript declaration files only)" — making it explicit this is TS-specific so an LLM doesn't misapply it to Python
|
||||
|
||||
**Why:** Without `__init__.py → entry`, the architecture analyzer would never recognize any Python file as an entry point via file-level patterns. The `hooks` pattern label was left as-is (it won't trigger on Python projects since they don't conventionally have a `hooks/` directory).
|
||||
|
||||
**Note on Node.js script:** The architecture analyzer's structural analysis script is hardcoded to `node`. This is correct to leave as-is — the script processes the JSON graph structure (file nodes, import edges), not the source language of the codebase being analyzed. The script's input/output is always JSON regardless of whether the project is Python or TypeScript.
|
||||
|
||||
**Regression risk:** Very low. Added rows to the directory pattern table and clarified file-level pattern descriptions. No existing patterns were removed or modified.
|
||||
|
||||
**How to verify:** Run on a Django project. Check that `migrations/` directory files land in `layer:data` and that `manage.py` gets tagged `entry`.
|
||||
|
||||
---
|
||||
|
||||
### 4. `tour-builder-prompt.md`
|
||||
|
||||
**What changed:**
|
||||
|
||||
**Entry point candidate scoring (Section C)** — Added Python entry points to the +3 filename list:
|
||||
- Added: `manage.py`, `app.py`, `wsgi.py`, `asgi.py`, `run.py`, `__main__.py`
|
||||
|
||||
Before this change, the entry point scoring had 8 TS/JS patterns vs 4 for all other languages. After: 8 TS/JS + 6 Python + 4 others.
|
||||
|
||||
**Why:** The tour builder uses entry point scores to decide Step 1 of the tour. For a Django project where `manage.py` exists, it should score highly. Without this, the tour might start from a random high-fan-in utility file instead of the actual entry point.
|
||||
|
||||
**The `languageLesson` example** was left as-is (TypeScript barrel files). This is just an illustrative example in the output format section — it does not affect how Python tours are generated. The language lessons section already lists Python-specific patterns (decorators, generators, context managers, metaclasses, protocols).
|
||||
|
||||
**Regression risk:** None. The scoring list is additive. TS/JS entry points retain their +3 scores.
|
||||
|
||||
**How to verify:** Run on a Django project. Check that `tour.json` starts from `manage.py` or `apps.py`/`wsgi.py` rather than a utility file.
|
||||
|
||||
---
|
||||
|
||||
### 5. `file-analyzer-prompt.md`
|
||||
|
||||
**What changed:**
|
||||
|
||||
**Tags indicators — barrel/entry-point detection** — Extended the `index.ts` rule:
|
||||
- Before: `Named index.ts at a directory root with re-exports = entry-point`
|
||||
- After: Added `__init__.py` at a package root with imports or re-exports = `entry-point`, and `manage.py` = `entry-point`
|
||||
|
||||
**Script execution example** — Added the Python equivalent command alongside the Node.js example. The base prompt already says "Choose the best language for this task — Node.js is recommended for TypeScript/JavaScript projects, Python for Python projects" (line 15), but the execution example only showed `node`. This created a contradiction. Now both are shown.
|
||||
|
||||
**Regression risk:** None. Additive changes only.
|
||||
|
||||
**How to verify:** Run on a Python project with a package structure. Check that `__init__.py` files at package roots get the `entry-point` or `barrel` tag rather than being treated as empty boilerplate files.
|
||||
|
||||
---
|
||||
|
||||
## New Files Created
|
||||
|
||||
### `django-analyzer-addendum.md`
|
||||
|
||||
A detailed reference injected into the file-analyzer and architecture-analyzer when Django is detected. Contains:
|
||||
- Canonical file roles table (15+ Django file types with appropriate tags)
|
||||
- Edge patterns to look for (URL routing graph, signal wiring, ORM relationships, serializer→model binding)
|
||||
- Layer assignment guide (7 layers: api, data, service, ui, middleware, config, test)
|
||||
- Notable `languageLesson` patterns (fat models, ORM lazy evaluation, CBV mixins, signal anti-patterns, app isolation)
|
||||
|
||||
**How it's injected:** SKILL.md reads this file and appends it to the base `file-analyzer-prompt.md` and `architecture-analyzer-prompt.md` content when `Django` appears in the detected frameworks list.
|
||||
|
||||
### `fastapi-analyzer-addendum.md`
|
||||
|
||||
A detailed reference for FastAPI and Flask projects, injected when either framework is detected. Contains two sections:
|
||||
|
||||
**FastAPI section:**
|
||||
- Canonical file roles (router files, Pydantic schemas, CRUD, dependencies, database session)
|
||||
- Edge patterns (router inclusion chain, DI tree, Pydantic inheritance, CRUD→model binding)
|
||||
- Layer assignment guide (7 layers)
|
||||
- Notable `languageLesson` patterns (DI as composition, Pydantic validation, async vs sync, route order)
|
||||
|
||||
**Flask section:**
|
||||
- Canonical file roles (blueprints, application factory, WTForms, Marshmallow)
|
||||
- Edge patterns (blueprint registration, extension coupling, before/after request hooks)
|
||||
- Layer assignment guide
|
||||
- Notable `languageLesson` patterns (factory pattern, blueprint modularity, extension `init_app` protocol)
|
||||
|
||||
**How it's injected:** Same mechanism as the Django addendum — SKILL.md appends it when `FastAPI` or `Flask` is in the detected frameworks list.
|
||||
|
||||
---
|
||||
|
||||
## What Was NOT Changed (And Why)
|
||||
|
||||
| Component | Rationale |
|
||||
|-----------|-----------|
|
||||
| Graph schema (`types.ts`, `schema.ts`) | Already language-agnostic. All 18 edge types work for Python patterns. |
|
||||
| `packages/core/src/plugins/tree-sitter-plugin.ts` | Still TS/JS only. Adding Python tree-sitter support is Phase 3 (separate PR). |
|
||||
| `packages/core/src/plugins/registry.ts` | Extension map already has `.py → python`. A Python plugin will register here in Phase 3. |
|
||||
| `packages/core/src/analyzer/language-lesson.ts` | Concept detection patterns. Phase 3 work. |
|
||||
| Dashboard, search engine, skills | Already language-agnostic. |
|
||||
| `tour-builder-prompt.md` language lessons example | The TypeScript barrel file example is illustrative only. Python tours will produce Python-specific `languageLesson` strings based on the language-lessons list (which already includes Python patterns). |
|
||||
| Architecture analyzer `node` script execution | The script analyzes the graph JSON, not the source language. `node` is always correct here. |
|
||||
| `hooks` directory pattern label | React-specific but harmless — Python projects don't conventionally have `hooks/` directories, so this label will never trigger on Python codebases. |
|
||||
|
||||
---
|
||||
|
||||
## Testing Checklist for Reviewer
|
||||
|
||||
For a Django project (e.g., a real Django app with `requirements.txt`):
|
||||
- [ ] `scan-result.json` has `frameworks: ["Django"]` (or similar)
|
||||
- [ ] `manage.py` is detected as `$ENTRY_POINT` in SKILL.md Phase 0
|
||||
- [ ] `manage.py` node gets tags including `entry-point`
|
||||
- [ ] `urls.py` files get `api-handler`, `routing` tags
|
||||
- [ ] `models.py` files get `data-model` tag
|
||||
- [ ] `migrations/` directory files land in `layer:data`
|
||||
- [ ] Tour Step 1 starts from `manage.py` or `wsgi.py`
|
||||
- [ ] No TypeScript-specific guidance appears in the analysis output
|
||||
|
||||
For a FastAPI project:
|
||||
- [ ] `scan-result.json` has `frameworks: ["FastAPI"]`
|
||||
- [ ] Router files get `api-handler`, `routing` tags
|
||||
- [ ] Pydantic schema files get `type-definition`, `serialization` tags
|
||||
- [ ] `dependencies.py` or `deps.py` gets `service` tag
|
||||
- [ ] `depends_on` edges appear between router files and their dependencies
|
||||
- [ ] `layer:types` exists with schema files
|
||||
|
||||
For an existing TypeScript project (regression check):
|
||||
- [ ] No Django/FastAPI addendum content appears in analysis
|
||||
- [ ] `frameworks: ["React"]` (or whatever was there before) unchanged
|
||||
- [ ] `src/index.ts` still detected as entry point
|
||||
- [ ] All existing layer assignments and tour steps unchanged
|
||||
@@ -54,7 +54,7 @@ Determine whether to run a full analysis or incremental update.
|
||||
find $PROJECT_ROOT -maxdepth 2 -type f -not -path '*/node_modules/*' -not -path '*/.git/*' -not -path '*/dist/*' | head -100
|
||||
```
|
||||
Store as `$DIR_TREE`.
|
||||
- Detect the project entry point by checking for common patterns (in order): `src/index.ts`, `src/main.ts`, `src/App.tsx`, `index.js`, `main.py`, `manage.py`, `app.py`, `wsgi.py`, `asgi.py`, `run.py`, `__main__.py`, `main.go`, `src/main.rs`. Store first match as `$ENTRY_POINT`.
|
||||
- Detect the project entry point by checking for common patterns (in order): `src/index.ts`, `src/main.ts`, `src/App.tsx`, `index.js`, `main.py`, `manage.py`, `app.py`, `wsgi.py`, `asgi.py`, `run.py`, `__main__.py`, `main.go`, `cmd/*/main.go`, `src/main.rs`, `src/lib.rs`, `src/main/java/**/Application.java`, `Program.cs`, `config.ru`, `index.php`. Store first match as `$ENTRY_POINT`.
|
||||
|
||||
---
|
||||
|
||||
@@ -98,7 +98,14 @@ After the subagent completes, read `$PROJECT_ROOT/.understand-anything/intermedi
|
||||
|
||||
Batch the file list from Phase 1 into groups of **5-10 files each** (aim for balanced batch sizes).
|
||||
|
||||
For each batch, dispatch a subagent using the prompt template at `./file-analyzer-prompt.md`. Run up to **3 subagents concurrently** using parallel dispatch. Read the template once. If any detected framework is `Django`, also read `./django-analyzer-addendum.md` and append its full content after the base template. If any detected framework is `FastAPI` or `Flask`, also read `./fastapi-analyzer-addendum.md` and append its full content after the base template. Then for each batch pass the combined template content as the subagent's prompt, appending the following additional context:
|
||||
For each batch, dispatch a subagent using the prompt template at `./file-analyzer-prompt.md`. Run up to **3 subagents concurrently** using parallel dispatch.
|
||||
|
||||
**Build the combined prompt template:**
|
||||
1. Read the base template at `./file-analyzer-prompt.md`.
|
||||
2. **Language context injection:** For each language detected in Phase 1, check if `./languages/<language-id>.md` exists. If it does, read it and append its content after the base template under a `## Language Context` header.
|
||||
3. **Framework addendum injection:** For each framework detected in Phase 1, check if `./frameworks/<framework-id-lowercase>.md` exists. If it does, read it and append its full content after the language context. This replaces any hardcoded framework-specific conditionals.
|
||||
|
||||
Then for each batch pass the combined template content as the subagent's prompt, appending the following additional context:
|
||||
|
||||
> **Additional context from main session:**
|
||||
>
|
||||
@@ -106,15 +113,7 @@ For each batch, dispatch a subagent using the prompt template at `./file-analyze
|
||||
> Frameworks detected: `<frameworks from Phase 1>`
|
||||
> Languages: `<languages from Phase 1>`
|
||||
>
|
||||
> Framework-specific guidance:
|
||||
> - If React/Next.js: files in `app/` or `pages/` are routes, `components/` are UI, `lib/` or `utils/` are utilities
|
||||
> - If Express/Fastify: files in `routes/` are API endpoints, `middleware/` is middleware, `models/` or `db/` is data
|
||||
> - If Python Django: `views.py` are controllers, `models.py` is data, `urls.py` is routing, `templates/` is UI, `serializers.py` is API serialization, `signals.py` is event wiring, `admin.py` is admin registration, `migrations/` is schema history
|
||||
> - If Python FastAPI: files with `@router.get/post/...` decorators are endpoints, `schemas.py` or `models.py` with Pydantic classes are request/response types, `dependencies.py` or `deps.py` holds `Depends()` providers, `routers/` or `api/` groups route modules
|
||||
> - If Python Flask: files with `@app.route` or `@blueprint.route` are endpoints, `blueprints/` or `views/` groups route modules, `models.py` with SQLAlchemy classes is data
|
||||
> - If Go: `cmd/` is entry points, `internal/` is private packages, `pkg/` is public packages
|
||||
>
|
||||
> Use this context to produce more accurate summaries and better classify file roles.
|
||||
> Use the language context and framework addendums (appended above) to produce more accurate summaries and better classify file roles.
|
||||
|
||||
Fill in batch-specific parameters below and dispatch:
|
||||
|
||||
@@ -160,7 +159,12 @@ Merge all file-analyzer results into a single set of nodes and edges. Then perfo
|
||||
|
||||
## Phase 4 — ARCHITECTURE
|
||||
|
||||
Dispatch a subagent using the prompt template at `./architecture-analyzer-prompt.md`. If any detected framework is `Django`, also read `./django-analyzer-addendum.md` and append its full content after the base template. If any detected framework is `FastAPI` or `Flask`, also read `./fastapi-analyzer-addendum.md` and append its full content after the base template. Pass the combined content as the subagent's prompt, appending the following additional context:
|
||||
**Build the combined prompt template:**
|
||||
1. Read the base template at `./architecture-analyzer-prompt.md`.
|
||||
2. **Language context injection:** For each language detected in Phase 1, check if `./languages/<language-id>.md` exists. If it does, read it and append its content after the base template under a `## Language Context` header.
|
||||
3. **Framework addendum injection:** For each framework detected in Phase 1, check if `./frameworks/<framework-id-lowercase>.md` exists. If it does, read it and append its full content after the language context.
|
||||
|
||||
Pass the combined content as the subagent's prompt, appending the following additional context:
|
||||
|
||||
> **Additional context from main session:**
|
||||
>
|
||||
@@ -171,15 +175,7 @@ Dispatch a subagent using the prompt template at `./architecture-analyzer-prompt
|
||||
> $DIR_TREE
|
||||
> ```
|
||||
>
|
||||
> Framework-specific layer hints:
|
||||
> - If React/Next.js: `app/` or `pages/` → UI Layer, `api/` → API Layer, `lib/` → Service Layer, `components/` → UI Layer
|
||||
> - If Express: `routes/` → API Layer, `controllers/` → Service Layer, `models/` → Data Layer, `middleware/` → Middleware Layer
|
||||
> - If Python Django: `views/` or `views.py` → API Layer, `models/` or `models.py` → Data Layer, `templates/` → UI Layer, `management/` → CLI Layer, `serializers.py` → API Layer, `signals.py` → Event Layer, `migrations/` → Data Layer
|
||||
> - If Python FastAPI: files with router decorators → API Layer, Pydantic schema files → Types Layer, `dependencies.py` or `deps.py` → Service Layer, `routers/` or `api/` → API Layer, database session/engine files → Data Layer
|
||||
> - If Python Flask: files with `@blueprint.route` → API Layer, `models.py` → Data Layer, `forms.py` → UI Layer, `extensions.py` → Config Layer
|
||||
> - If Go: `cmd/` → Entry Points, `internal/` → Service Layer, `pkg/` → Shared Library, `api/` → API Layer
|
||||
>
|
||||
> Use the directory tree and framework hints to inform layer assignments. Directory structure is strong evidence for layer boundaries.
|
||||
> Use the directory tree, language context, and framework addendums (appended above) to inform layer assignments. Directory structure is strong evidence for layer boundaries.
|
||||
|
||||
Pass these parameters in the dispatch prompt:
|
||||
|
||||
|
||||
@@ -87,13 +87,31 @@ Classify each directory name against known architectural patterns:
|
||||
| `templatetags` | `utility` |
|
||||
| `signals` | `service` |
|
||||
| `serializers` | `api` |
|
||||
| `cmd` | `entry` |
|
||||
| `internal` | `service` |
|
||||
| `pkg` | `utility` |
|
||||
| `src/main/java` | `service` |
|
||||
| `src/test/java` | `test` |
|
||||
| `dto`, `request`, `response` | `types` |
|
||||
| `entity` | `data` |
|
||||
| `controller` | `api` |
|
||||
| `routers` | `api` |
|
||||
| `composables` | `service` |
|
||||
| `blueprints` | `api` |
|
||||
| `mailers`, `jobs`, `channels` | `service` |
|
||||
| `bin` | `entry` |
|
||||
|
||||
Also check file-level patterns:
|
||||
- Files matching `*.test.*` or `*.spec.*` or `test_*.py` -> `test`
|
||||
- Files matching `*.test.*` or `*.spec.*` or `test_*.py` or `*_test.go` or `*Test.java` or `*_spec.rb` or `*Test.php` or `*Tests.cs` -> `test`
|
||||
- Files matching `*.d.ts` -> `types` (TypeScript declaration files only)
|
||||
- Files named `index.ts`, `index.js`, or `__init__.py` at a package/directory root -> `entry`
|
||||
- Files named `manage.py` at the project root -> `entry` (Django management entry point)
|
||||
- Files named `wsgi.py` or `asgi.py` -> `config` (Python WSGI/ASGI server config)
|
||||
- Files named `main.go` at `cmd/*/` -> `entry` (Go binary entry points)
|
||||
- Files named `main.rs` or `lib.rs` at `src/` -> `entry` (Rust crate roots)
|
||||
- Files named `Application.java` or `Program.cs` -> `entry` (JVM / .NET entry points)
|
||||
- Files named `config.ru` -> `entry` (Ruby Rack entry point)
|
||||
- Files named `Cargo.toml`, `go.mod`, `Gemfile`, `pom.xml`, `build.gradle`, `composer.json` -> `config` (language-level project config)
|
||||
|
||||
**F. Dependency Direction**
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ For each file in the batch provided to you, extract structural data via a script
|
||||
|
||||
## Phase 1 -- Structural Extraction Script
|
||||
|
||||
Write a script that reads each source file in your batch and extracts deterministic structural information. Choose the best language for this task -- Node.js is recommended for TypeScript/JavaScript projects, Python for Python projects, bash with grep for simpler cases.
|
||||
Write a script that reads each source file in your batch and extracts deterministic structural information. Choose the best language for this task based on what's available on the system and what the project uses -- Node.js, Python, or bash with grep are all valid choices.
|
||||
|
||||
### Script Requirements
|
||||
|
||||
@@ -172,6 +172,12 @@ Indicators from script data:
|
||||
- Named `index.ts` or `index.js` at a directory root with re-exports = `entry-point` (JavaScript/TypeScript barrel)
|
||||
- Named `__init__.py` at a package root with imports or re-exports = `entry-point` (Python package barrel)
|
||||
- Named `manage.py` = `entry-point` (Django management script)
|
||||
- Named `main.go` in `cmd/` directory = `entry-point` (Go binary)
|
||||
- Named `main.rs` or `lib.rs` in `src/` = `entry-point` (Rust crate root)
|
||||
- Named `Application.java` or `Main.java` = `entry-point` (Java application)
|
||||
- Named `Program.cs` = `entry-point` (.NET application)
|
||||
- Named `config.ru` = `entry-point` (Ruby Rack server)
|
||||
- Named `mod.rs` in a directory = `barrel` (Rust module barrel)
|
||||
|
||||
**Language Notes** (optional, your expert judgment):
|
||||
If the structural data reveals notable language-specific patterns (e.g., many generic type parameters, decorator usage, complex trait bounds), add a brief `languageNotes` string. Only add this when genuinely educational.
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
# Express Framework Addendum
|
||||
|
||||
> Injected into file-analyzer and architecture-analyzer prompts when Express is detected.
|
||||
> Do NOT use as a standalone prompt — always appended to the base prompt template.
|
||||
|
||||
## Express Project Structure
|
||||
|
||||
When analyzing an Express project, apply these additional conventions on top of the base analysis rules.
|
||||
|
||||
### Canonical File Roles
|
||||
|
||||
| File / Pattern | Role | Tags |
|
||||
|---|---|---|
|
||||
| `app.js`, `app.ts` | Application entry point — creates Express app, mounts middleware and routes | `entry-point`, `config` |
|
||||
| `server.js`, `server.ts`, `index.js`, `index.ts` | Server bootstrap — starts HTTP listener, may import app | `entry-point`, `config` |
|
||||
| `routes/*.js`, `routes/*.ts` | Route definitions — map HTTP methods and paths to handlers | `api-handler`, `routing` |
|
||||
| `controllers/*.js`, `controllers/*.ts` | Request handlers — process requests, orchestrate services, return responses | `api-handler`, `service` |
|
||||
| `models/*.js`, `models/*.ts` | Data models — Mongoose schemas, Sequelize models, or plain data definitions | `data-model` |
|
||||
| `middleware/*.js`, `middleware/*.ts` | Middleware functions — authentication, logging, validation, error handling | `middleware` |
|
||||
| `services/*.js`, `services/*.ts` | Business logic — domain operations decoupled from HTTP layer | `service` |
|
||||
| `db/*.js`, `db/*.ts`, `database/*.js` | Database connection and configuration | `data-model`, `config` |
|
||||
| `config/*.js`, `config/*.ts` | Application configuration — environment variables, feature flags | `config` |
|
||||
| `validators/*.js`, `validators/*.ts` | Request validation schemas (Joi, Zod, express-validator) | `validation`, `utility` |
|
||||
| `utils/*.js`, `utils/*.ts` | Shared utility functions | `utility` |
|
||||
| `tests/*.js`, `test/*.js`, `__tests__/*.js` | Unit and integration tests | `test` |
|
||||
|
||||
### Edge Patterns to Look For
|
||||
|
||||
**Route mounting** — When `app.use('/api/users', usersRouter)` mounts a router, create `depends_on` edges from the main app to the router module. These edges represent the HTTP routing tree.
|
||||
|
||||
**Middleware chain** — When `app.use(cors())`, `app.use(authMiddleware)`, or `router.use(validate)` registers middleware, create middleware edges from the app or router to the middleware function. Order matters — middleware executes in registration order.
|
||||
|
||||
**Controller-to-service calls** — When a controller imports and calls a service function, create `depends_on` edges from the controller to the service. This represents the separation between HTTP handling and business logic.
|
||||
|
||||
**Model relationships** — When models reference each other (Mongoose `ref`, Sequelize associations), create `depends_on` edges between model files with descriptions indicating the relationship type.
|
||||
|
||||
### Architectural Layers for Express
|
||||
|
||||
Assign nodes to these layers when detected:
|
||||
|
||||
| Layer ID | Layer Name | What Goes Here |
|
||||
|---|---|---|
|
||||
| `layer:api` | API Layer | `routes/`, `controllers/`, request validators |
|
||||
| `layer:data` | Data Layer | `models/`, `db/`, migration files, seeders |
|
||||
| `layer:service` | Service Layer | `services/`, business logic modules |
|
||||
| `layer:middleware` | Middleware Layer | `middleware/`, error handlers, authentication, logging |
|
||||
| `layer:config` | Config Layer | `app.js`, `config/`, environment setup, `server.js` |
|
||||
| `layer:utility` | Utility Layer | `utils/`, `helpers/`, shared pure functions |
|
||||
| `layer:test` | Test Layer | `tests/`, `__tests__/`, `*.test.js`, `*.spec.js` |
|
||||
|
||||
### Notable Patterns to Capture in languageLesson
|
||||
|
||||
- **Middleware chain (req, res, next)**: Express processes requests through a pipeline of middleware functions — each receives the request, response, and a `next()` callback to pass control forward
|
||||
- **Error-handling middleware (4 params)**: Middleware with signature `(err, req, res, next)` catches errors — must be registered after all routes to act as a global error handler
|
||||
- **Router modularity**: `express.Router()` creates modular, mountable route handlers that can be composed into the main app at different path prefixes
|
||||
- **MVC pattern**: Express apps commonly separate concerns into Models (data), Views (response formatting), and Controllers (request handling)
|
||||
- **Body parsing and validation**: Request body parsing (`express.json()`, `express.urlencoded()`) and validation (Joi, Zod, express-validator) are middleware concerns applied before route handlers
|
||||
+4
-55
@@ -1,13 +1,13 @@
|
||||
# FastAPI / Flask Framework Addendum
|
||||
# FastAPI Framework Addendum
|
||||
|
||||
> Injected into file-analyzer and architecture-analyzer prompts when FastAPI or Flask is detected.
|
||||
> Injected into file-analyzer and architecture-analyzer prompts when FastAPI is detected.
|
||||
> Do NOT use as a standalone prompt — always appended to the base prompt template.
|
||||
|
||||
## FastAPI Project Structure
|
||||
|
||||
When analyzing a FastAPI project, apply these additional conventions on top of the base analysis rules.
|
||||
|
||||
### Canonical File Roles — FastAPI
|
||||
### Canonical File Roles
|
||||
|
||||
| File / Pattern | Role | Tags |
|
||||
|---|---|---|
|
||||
@@ -26,7 +26,7 @@ When analyzing a FastAPI project, apply these additional conventions on top of t
|
||||
| `*/tests/*.py`, `test_*.py` | pytest test files | `test` |
|
||||
| `conftest.py` | pytest fixtures and test configuration | `test`, `config` |
|
||||
|
||||
### Edge Patterns to Look For — FastAPI
|
||||
### Edge Patterns to Look For
|
||||
|
||||
**Router inclusion chain** — When `app.include_router(some_router, prefix="/api")` appears in `main.py` or a router aggregator, create `imports` + `depends_on` edges from the main app file to each router module. This builds the URL hierarchy graph.
|
||||
|
||||
@@ -56,54 +56,3 @@ When analyzing a FastAPI project, apply these additional conventions on top of t
|
||||
- **Pydantic for validation**: Request bodies, query params, and path params are automatically validated by Pydantic — invalid input raises `422 Unprocessable Entity` before your code runs
|
||||
- **Async endpoints**: `async def` routes run in the event loop; `def` routes run in a threadpool — mixing them incorrectly can cause performance issues
|
||||
- **Path operation order**: FastAPI matches routes in declaration order; a catch-all route before a specific one will shadow it
|
||||
|
||||
---
|
||||
|
||||
## Flask Project Structure
|
||||
|
||||
When analyzing a Flask project, apply these additional conventions on top of the base analysis rules.
|
||||
|
||||
### Canonical File Roles — Flask
|
||||
|
||||
| File / Pattern | Role | Tags |
|
||||
|---|---|---|
|
||||
| `app.py`, `__init__.py` (in app package) | Application factory (`create_app()`) or direct `Flask(__name__)` instance | `entry-point`, `config` |
|
||||
| `run.py`, `wsgi.py` | Production/dev server entry point | `entry-point`, `config` |
|
||||
| `*/views.py`, `*/routes.py` | Route handler functions with `@app.route` or `@blueprint.route` | `api-handler`, `routing` |
|
||||
| `*/blueprints/*.py`, `*/api/*.py` | Blueprint modules — group routes by feature | `api-handler`, `routing` |
|
||||
| `*/models.py` | SQLAlchemy models or other ORM models | `data-model` |
|
||||
| `*/forms.py` | WTForms form classes | `validation`, `ui` |
|
||||
| `*/schemas.py` | Marshmallow serialization schemas | `serialization`, `type-definition` |
|
||||
| `*/config.py` | Config classes (`DevelopmentConfig`, `ProductionConfig`) | `config` |
|
||||
| `*/extensions.py` | Flask extension initialization (`db = SQLAlchemy()`, `login_manager = LoginManager()`) | `config`, `singleton` |
|
||||
| `*/decorators.py` | Custom route decorators (auth guards, rate limiting) | `middleware`, `utility` |
|
||||
| `*/utils.py`, `*/helpers.py` | Shared utility functions | `utility` |
|
||||
| `*/templates/**/*.html` | Jinja2 templates | `ui` |
|
||||
| `*/static/` | CSS, JS, and asset files | `assets` |
|
||||
| `*/tests/*.py`, `test_*.py` | pytest or unittest test files | `test` |
|
||||
|
||||
### Edge Patterns to Look For — Flask
|
||||
|
||||
**Blueprint registration** — When `app.register_blueprint(bp, url_prefix='/api')` appears in the application factory, create `depends_on` edges from the app factory to each blueprint module.
|
||||
|
||||
**Extension coupling** — When a view imports from `extensions.py` (e.g., `from .extensions import db, login_manager`), create `imports` edges to show which views depend on which extensions.
|
||||
|
||||
**Before/after request hooks** — When `@app.before_request` or `@blueprint.before_request` decorates a function, create `middleware` edges from those functions to the app/blueprint they attach to.
|
||||
|
||||
### Architectural Layers for Flask
|
||||
|
||||
| Layer ID | Layer Name | What Goes Here |
|
||||
|---|---|---|
|
||||
| `layer:api` | API Layer | Blueprint route files, view functions |
|
||||
| `layer:data` | Data Layer | `models.py`, database migration files |
|
||||
| `layer:service` | Service Layer | Business logic modules, `schemas.py`, service classes |
|
||||
| `layer:ui` | UI Layer | `templates/`, `forms.py`, `static/` |
|
||||
| `layer:config` | Config Layer | `app.py` factory, `config.py`, `extensions.py` |
|
||||
| `layer:middleware` | Middleware Layer | `decorators.py`, before/after request hooks |
|
||||
| `layer:test` | Test Layer | Test files, `conftest.py` |
|
||||
|
||||
### Notable Patterns to Capture in languageLesson
|
||||
|
||||
- **Application factory pattern**: `create_app()` functions allow multiple app instances (e.g., for testing) and delay extension initialization — avoids circular imports
|
||||
- **Blueprint modularity**: Blueprints group related routes, templates, and static files; they are registered on the app with a URL prefix, making them independently testable
|
||||
- **Flask extension protocol**: Extensions follow `init_app(app)` for lazy initialization — the extension object is created globally but bound to an app instance later
|
||||
@@ -0,0 +1,53 @@
|
||||
# Flask Framework Addendum
|
||||
|
||||
> Injected into file-analyzer and architecture-analyzer prompts when Flask is detected.
|
||||
> Do NOT use as a standalone prompt — always appended to the base prompt template.
|
||||
|
||||
## Flask Project Structure
|
||||
|
||||
When analyzing a Flask project, apply these additional conventions on top of the base analysis rules.
|
||||
|
||||
### Canonical File Roles
|
||||
|
||||
| File / Pattern | Role | Tags |
|
||||
|---|---|---|
|
||||
| `app.py`, `__init__.py` (in app package) | Application factory (`create_app()`) or direct `Flask(__name__)` instance | `entry-point`, `config` |
|
||||
| `run.py`, `wsgi.py` | Production/dev server entry point | `entry-point`, `config` |
|
||||
| `*/views.py`, `*/routes.py` | Route handler functions with `@app.route` or `@blueprint.route` | `api-handler`, `routing` |
|
||||
| `*/blueprints/*.py`, `*/api/*.py` | Blueprint modules — group routes by feature | `api-handler`, `routing` |
|
||||
| `*/models.py` | SQLAlchemy models or other ORM models | `data-model` |
|
||||
| `*/forms.py` | WTForms form classes | `validation`, `ui` |
|
||||
| `*/schemas.py` | Marshmallow serialization schemas | `serialization`, `type-definition` |
|
||||
| `*/config.py` | Config classes (`DevelopmentConfig`, `ProductionConfig`) | `config` |
|
||||
| `*/extensions.py` | Flask extension initialization (`db = SQLAlchemy()`, `login_manager = LoginManager()`) | `config`, `singleton` |
|
||||
| `*/decorators.py` | Custom route decorators (auth guards, rate limiting) | `middleware`, `utility` |
|
||||
| `*/utils.py`, `*/helpers.py` | Shared utility functions | `utility` |
|
||||
| `*/templates/**/*.html` | Jinja2 templates | `ui` |
|
||||
| `*/static/` | CSS, JS, and asset files | `assets` |
|
||||
| `*/tests/*.py`, `test_*.py` | pytest or unittest test files | `test` |
|
||||
|
||||
### Edge Patterns to Look For
|
||||
|
||||
**Blueprint registration** — When `app.register_blueprint(bp, url_prefix='/api')` appears in the application factory, create `depends_on` edges from the app factory to each blueprint module.
|
||||
|
||||
**Extension coupling** — When a view imports from `extensions.py` (e.g., `from .extensions import db, login_manager`), create `imports` edges to show which views depend on which extensions.
|
||||
|
||||
**Before/after request hooks** — When `@app.before_request` or `@blueprint.before_request` decorates a function, create `middleware` edges from those functions to the app/blueprint they attach to.
|
||||
|
||||
### Architectural Layers for Flask
|
||||
|
||||
| Layer ID | Layer Name | What Goes Here |
|
||||
|---|---|---|
|
||||
| `layer:api` | API Layer | Blueprint route files, view functions |
|
||||
| `layer:data` | Data Layer | `models.py`, database migration files |
|
||||
| `layer:service` | Service Layer | Business logic modules, `schemas.py`, service classes |
|
||||
| `layer:ui` | UI Layer | `templates/`, `forms.py`, `static/` |
|
||||
| `layer:config` | Config Layer | `app.py` factory, `config.py`, `extensions.py` |
|
||||
| `layer:middleware` | Middleware Layer | `decorators.py`, before/after request hooks |
|
||||
| `layer:test` | Test Layer | Test files, `conftest.py` |
|
||||
|
||||
### Notable Patterns to Capture in languageLesson
|
||||
|
||||
- **Application factory pattern**: `create_app()` functions allow multiple app instances (e.g., for testing) and delay extension initialization — avoids circular imports
|
||||
- **Blueprint modularity**: Blueprints group related routes, templates, and static files; they are registered on the app with a URL prefix, making them independently testable
|
||||
- **Flask extension protocol**: Extensions follow `init_app(app)` for lazy initialization — the extension object is created globally but bound to an app instance later
|
||||
@@ -0,0 +1,59 @@
|
||||
# Gin (Go) Framework Addendum
|
||||
|
||||
> Injected into file-analyzer and architecture-analyzer prompts when Gin is detected.
|
||||
> Do NOT use as a standalone prompt — always appended to the base prompt template.
|
||||
|
||||
## Gin Project Structure
|
||||
|
||||
When analyzing a Gin project, apply these additional conventions on top of the base analysis rules.
|
||||
|
||||
### Canonical File Roles
|
||||
|
||||
| File / Pattern | Role | Tags |
|
||||
|---|---|---|
|
||||
| `main.go` | Application entry point — initializes the Gin engine, registers routes, starts the server | `entry-point`, `config` |
|
||||
| `cmd/*.go`, `cmd/**/*.go` | CLI entry points — multiple binaries in a multi-command project | `entry-point`, `config` |
|
||||
| `handlers/*.go`, `handler/*.go` | HTTP handlers — process requests with `gin.Context` | `api-handler` |
|
||||
| `controllers/*.go`, `controller/*.go` | Controllers — alternative naming for HTTP handlers | `api-handler` |
|
||||
| `routes/*.go`, `router/*.go` | Route definitions — register endpoints and route groups | `routing`, `config` |
|
||||
| `models/*.go`, `model/*.go` | Data models — struct definitions mapped to database tables | `data-model` |
|
||||
| `middleware/*.go` | Middleware functions — authentication, logging, CORS, rate limiting | `middleware` |
|
||||
| `services/*.go`, `service/*.go` | Business logic — domain operations decoupled from HTTP layer | `service` |
|
||||
| `repository/*.go`, `repo/*.go` | Data access layer — database queries and persistence logic | `data-model`, `service` |
|
||||
| `config/*.go`, `config.go` | Application configuration — environment loading, struct-based config | `config` |
|
||||
| `dto/*.go` | Data transfer objects — request and response structs | `type-definition` |
|
||||
| `utils/*.go`, `pkg/*.go` | Shared utility packages | `utility` |
|
||||
| `*_test.go` | Unit and integration tests | `test` |
|
||||
|
||||
### Edge Patterns to Look For
|
||||
|
||||
**Route group registration** — When `r.Group("/api")` creates a route group and registers handlers, create `configures` edges from the route definition file to each handler. Route groups organize endpoints by prefix and shared middleware.
|
||||
|
||||
**Handler-to-service calls** — When a handler function calls a service method, create `depends_on` edges from the handler to the service. This represents the separation between HTTP handling and business logic.
|
||||
|
||||
**Service-to-repository calls** — When a service calls a repository method for data access, create `depends_on` edges from the service to the repository. This represents the data access abstraction.
|
||||
|
||||
**Middleware chaining** — When `r.Use(middleware)` or a route group applies middleware, create middleware edges from the router or group to the middleware function. Middleware executes in registration order.
|
||||
|
||||
### Architectural Layers for Gin
|
||||
|
||||
Assign nodes to these layers when detected:
|
||||
|
||||
| Layer ID | Layer Name | What Goes Here |
|
||||
|---|---|---|
|
||||
| `layer:api` | API Layer | `handlers/`, `controllers/`, HTTP handler functions |
|
||||
| `layer:data` | Data Layer | `models/`, `repository/`, database access, migrations |
|
||||
| `layer:service` | Service Layer | `services/`, business logic |
|
||||
| `layer:middleware` | Middleware Layer | `middleware/`, authentication, logging, rate limiting |
|
||||
| `layer:config` | Config Layer | `main.go`, `routes/`, `config/`, environment setup |
|
||||
| `layer:utility` | Utility Layer | `utils/`, `pkg/`, shared helper packages |
|
||||
| `layer:test` | Test Layer | `*_test.go`, test fixtures, test helpers |
|
||||
|
||||
### Notable Patterns to Capture in languageLesson
|
||||
|
||||
- **Handler functions with gin.Context**: Every Gin handler receives a `*gin.Context` parameter — it provides request parsing (`c.Bind`, `c.Param`, `c.Query`), response writing (`c.JSON`, `c.HTML`), and control flow (`c.Abort`, `c.Next`)
|
||||
- **Middleware chain with c.Next()**: Middleware calls `c.Next()` to pass control to the next handler in the chain — code before `c.Next()` runs pre-handler, code after runs post-handler
|
||||
- **Route grouping for modular APIs**: `r.Group("/v1")` creates modular sub-routers that can have their own middleware stack — enables versioning and access control at the group level
|
||||
- **Dependency injection via constructors (no framework DI)**: Go has no DI framework — dependencies are passed as constructor parameters (e.g., `NewUserHandler(userService)`) and stored as struct fields
|
||||
- **Interface-driven design for testability**: Services and repositories are defined as interfaces — handlers depend on the interface, enabling mock implementations in tests
|
||||
- **Error handling with gin.Error**: Gin collects errors via `c.Error(err)` — middleware can inspect `c.Errors` after handler execution to implement centralized error logging and response formatting
|
||||
@@ -0,0 +1,59 @@
|
||||
# Next.js Framework Addendum
|
||||
|
||||
> Injected into file-analyzer and architecture-analyzer prompts when Next.js is detected.
|
||||
> Do NOT use as a standalone prompt — always appended to the base prompt template.
|
||||
|
||||
## Next.js Project Structure
|
||||
|
||||
When analyzing a Next.js project, apply these additional conventions on top of the base analysis rules.
|
||||
|
||||
### Canonical File Roles
|
||||
|
||||
| File / Pattern | Role | Tags |
|
||||
|---|---|---|
|
||||
| `app/layout.tsx` | Root layout — wraps all pages, defines HTML shell and global providers | `entry-point`, `config`, `ui` |
|
||||
| `app/page.tsx` | Root page component — renders at `/` | `ui`, `routing` |
|
||||
| `app/**/page.tsx` | Route page components — file path determines URL | `ui`, `routing` |
|
||||
| `app/**/layout.tsx` | Nested layouts — wrap child routes with shared UI | `ui`, `config` |
|
||||
| `app/**/loading.tsx` | Loading UI — shown as Suspense fallback during route transitions | `ui` |
|
||||
| `app/**/error.tsx` | Error boundary — catches errors in the route segment | `ui` |
|
||||
| `app/**/not-found.tsx` | 404 UI — shown when `notFound()` is called | `ui` |
|
||||
| `app/api/**/route.ts` | API route handlers — serverless endpoint functions (GET, POST, etc.) | `api-handler` |
|
||||
| `middleware.ts` | Edge middleware — intercepts requests before they reach routes | `middleware` |
|
||||
| `lib/*.ts`, `lib/**/*.ts` | Shared server-side utilities, data access, and business logic | `service` |
|
||||
| `components/*.tsx`, `components/**/*.tsx` | Reusable UI components | `ui` |
|
||||
| `next.config.js`, `next.config.mjs`, `next.config.ts` | Next.js configuration — redirects, rewrites, env, webpack overrides | `config` |
|
||||
| `actions/*.ts`, `app/**/actions.ts` | Server Actions — server-side mutation functions callable from client | `service`, `api-handler` |
|
||||
|
||||
### Edge Patterns to Look For
|
||||
|
||||
**Layout nesting** — When `app/foo/layout.tsx` wraps `app/foo/page.tsx` and `app/foo/bar/page.tsx`, create `contains` edges from the layout to the pages it wraps. Layouts compose via the file-system hierarchy.
|
||||
|
||||
**API route handlers** — When a `route.ts` file exports named functions (GET, POST, PUT, DELETE), create edges from consuming components or server actions to the route handler based on fetch calls.
|
||||
|
||||
**Server/Client component boundary** — Files with `"use client"` directive at the top are Client Components. All other components in the `app/` directory are Server Components by default. Create `depends_on` edges that cross this boundary and note the boundary in the edge description.
|
||||
|
||||
**Parallel routes** — When `app/@slot/page.tsx` patterns appear, create `contains` edges from the parent layout to each parallel slot. These render simultaneously in the same layout.
|
||||
|
||||
**Route groups** — Directories wrapped in parentheses `(group)` organize routes without affecting the URL path. Note these in node descriptions.
|
||||
|
||||
### Architectural Layers for Next.js
|
||||
|
||||
Assign nodes to these layers when detected:
|
||||
|
||||
| Layer ID | Layer Name | What Goes Here |
|
||||
|---|---|---|
|
||||
| `layer:ui` | UI Layer | `app/**/page.tsx`, `app/**/layout.tsx`, `components/`, loading/error boundaries |
|
||||
| `layer:api` | API Layer | `app/api/**/route.ts`, API route handlers |
|
||||
| `layer:service` | Service Layer | `lib/`, server actions, data-fetching utilities |
|
||||
| `layer:middleware` | Middleware Layer | `middleware.ts`, edge functions |
|
||||
| `layer:config` | Config Layer | `next.config.*`, root layout, `tailwind.config.*`, environment setup |
|
||||
| `layer:test` | Test Layer | `__tests__/`, `*.test.tsx`, `*.spec.tsx`, `e2e/` |
|
||||
|
||||
### Notable Patterns to Capture in languageLesson
|
||||
|
||||
- **Server Components by default**: Components in the `app/` directory are Server Components — no JavaScript is sent to the client unless `"use client"` is declared
|
||||
- **Server Actions for mutations**: Functions marked with `"use server"` can be called directly from client components, replacing traditional API routes for form submissions and mutations
|
||||
- **App Router file conventions**: Special files (`page`, `layout`, `loading`, `error`, `not-found`, `route`) define behavior by naming convention within the file-system router
|
||||
- **ISR and static generation**: `generateStaticParams` pre-renders pages at build time; revalidation strategies control cache freshness
|
||||
- **Parallel and intercepting routes**: `@slot` directories enable parallel rendering; `(.)` prefix directories enable route interception for modal patterns
|
||||
@@ -0,0 +1,65 @@
|
||||
# Ruby on Rails Framework Addendum
|
||||
|
||||
> Injected into file-analyzer and architecture-analyzer prompts when Rails is detected.
|
||||
> Do NOT use as a standalone prompt — always appended to the base prompt template.
|
||||
|
||||
## Rails Project Structure
|
||||
|
||||
When analyzing a Ruby on Rails project, apply these additional conventions on top of the base analysis rules.
|
||||
|
||||
### Canonical File Roles
|
||||
|
||||
| File / Pattern | Role | Tags |
|
||||
|---|---|---|
|
||||
| `config.ru` | Rack entry point — boots the Rails application for the web server | `entry-point` |
|
||||
| `config/application.rb` | Application configuration — sets up Rails, loads gems, configures middleware | `entry-point`, `config` |
|
||||
| `app/controllers/*_controller.rb` | Controllers — handle HTTP requests, orchestrate models, render responses | `api-handler` |
|
||||
| `app/controllers/concerns/*.rb` | Controller concerns — shared controller behavior via mixins | `middleware`, `utility` |
|
||||
| `app/models/*.rb` | ActiveRecord models — map to database tables, contain validations and associations | `data-model` |
|
||||
| `app/models/concerns/*.rb` | Model concerns — shared model behavior via mixins | `utility` |
|
||||
| `app/views/**/*.erb`, `app/views/**/*.haml` | View templates — HTML rendering with embedded Ruby | `ui` |
|
||||
| `app/helpers/*_helper.rb` | View helpers — utility methods available in templates | `utility` |
|
||||
| `app/mailers/*_mailer.rb` | Action Mailer classes — send email notifications | `service` |
|
||||
| `app/jobs/*_job.rb` | Active Job classes — background job processing | `service` |
|
||||
| `app/channels/*_channel.rb` | Action Cable channels — WebSocket communication | `service` |
|
||||
| `app/serializers/*_serializer.rb` | API serializers — JSON response formatting (ActiveModelSerializers, Blueprinter) | `api-handler`, `utility` |
|
||||
| `app/services/*.rb` | Service objects — encapsulate complex business logic | `service` |
|
||||
| `db/migrate/*.rb` | Database migrations — schema changes versioned by timestamp | `config`, `data-model` |
|
||||
| `db/schema.rb`, `db/structure.sql` | Generated schema snapshot — current database structure | `data-model`, `config` |
|
||||
| `config/routes.rb` | Route definitions — maps URLs to controller actions | `routing`, `config` |
|
||||
| `config/initializers/*.rb` | Initializers — run once at boot to configure gems and services | `config` |
|
||||
| `lib/**/*.rb` | Library code — custom classes, Rake tasks, extensions | `utility`, `service` |
|
||||
| `spec/**/*_spec.rb`, `test/**/*_test.rb` | RSpec or Minitest test files | `test` |
|
||||
|
||||
### Edge Patterns to Look For
|
||||
|
||||
**Route-to-controller mapping** — When `config/routes.rb` defines `resources :users` or `get '/foo', to: 'bar#baz'`, create `configures` edges from the routes file to the corresponding controller. RESTful resources generate a full set of action mappings.
|
||||
|
||||
**ActiveRecord associations** — When models define `has_many`, `belongs_to`, `has_one`, or `has_and_belongs_to_many`, create `depends_on` edges between model files with descriptions indicating the association type and direction.
|
||||
|
||||
**Controller-to-model** — When a controller calls model methods (`User.find`, `@post.save`), create `depends_on` edges from the controller to the model. Controllers are the primary consumers of model data.
|
||||
|
||||
**Callbacks** — When models or controllers use `before_action`, `after_save`, `before_validation`, or similar callbacks, note these as middleware-like edges. Callbacks create implicit execution paths that are not visible from the call site.
|
||||
|
||||
### Architectural Layers for Rails
|
||||
|
||||
Assign nodes to these layers when detected:
|
||||
|
||||
| Layer ID | Layer Name | What Goes Here |
|
||||
|---|---|---|
|
||||
| `layer:api` | API Layer | `app/controllers/`, `app/serializers/`, API-specific controllers |
|
||||
| `layer:data` | Data Layer | `app/models/`, `db/migrate/`, `db/schema.rb` |
|
||||
| `layer:ui` | UI Layer | `app/views/`, `app/helpers/`, `app/assets/`, `app/javascript/` |
|
||||
| `layer:service` | Service Layer | `app/mailers/`, `app/jobs/`, `app/channels/`, `app/services/`, `lib/` |
|
||||
| `layer:config` | Config Layer | `config/routes.rb`, `config/initializers/`, `config/application.rb`, `config.ru` |
|
||||
| `layer:middleware` | Middleware Layer | `app/middleware/`, controller concerns, Rack middleware |
|
||||
| `layer:test` | Test Layer | `spec/`, `test/`, `*.spec.rb`, `*_test.rb` |
|
||||
|
||||
### Notable Patterns to Capture in languageLesson
|
||||
|
||||
- **Convention over configuration**: Rails derives routing, table names, and file locations from naming conventions — `UsersController` maps to `users_controller.rb`, handles `/users`, and queries the `users` table
|
||||
- **ActiveRecord pattern**: Models are database wrappers — each model class maps to a table, instances map to rows, and attributes map to columns with automatic type coercion
|
||||
- **Concerns for shared behavior**: `ActiveSupport::Concern` modules are mixins included in models or controllers to share validations, scopes, callbacks, and methods across classes
|
||||
- **Strong parameters for mass-assignment protection**: `params.require(:user).permit(:name, :email)` whitelists attributes — controllers must explicitly declare which fields can be set from user input
|
||||
- **RESTful resource routing**: `resources :posts` generates seven standard CRUD routes — Rails strongly encourages RESTful design where each controller maps to a resource
|
||||
- **Callbacks and observers**: `before_save`, `after_create`, and similar callbacks inject logic into the object lifecycle — they create invisible execution paths that can be difficult to trace
|
||||
@@ -0,0 +1,55 @@
|
||||
# React Framework Addendum
|
||||
|
||||
> Injected into file-analyzer and architecture-analyzer prompts when React is detected.
|
||||
> Do NOT use as a standalone prompt — always appended to the base prompt template.
|
||||
|
||||
## React Project Structure
|
||||
|
||||
When analyzing a React project, apply these additional conventions on top of the base analysis rules.
|
||||
|
||||
### Canonical File Roles
|
||||
|
||||
| File / Pattern | Role | Tags |
|
||||
|---|---|---|
|
||||
| `src/App.tsx` | Root application component — mounts providers, router, and top-level layout | `entry-point`, `ui` |
|
||||
| `components/*.tsx`, `components/**/*.tsx` | Reusable UI components | `ui` |
|
||||
| `hooks/*.ts`, `hooks/*.tsx` | Custom React hooks — encapsulate reusable stateful logic | `service`, `utility` |
|
||||
| `contexts/*.tsx`, `context/*.tsx` | React Context providers and consumers — shared state across component tree | `service`, `state` |
|
||||
| `pages/*.tsx`, `views/*.tsx` | Page-level components mapped to routes | `ui`, `routing` |
|
||||
| `utils/*.ts`, `helpers/*.ts` | Pure utility functions — formatting, validation, transformations | `utility` |
|
||||
| `types/*.ts`, `types/*.d.ts` | TypeScript type definitions and interfaces | `type-definition` |
|
||||
| `services/*.ts`, `api/*.ts` | API client functions and data-fetching logic | `service` |
|
||||
| `store/*.ts`, `slices/*.ts` | State management (Redux, Zustand, etc.) | `service`, `state` |
|
||||
| `constants/*.ts` | Application-wide constants and enums | `config` |
|
||||
| `__tests__/*.tsx`, `*.test.tsx`, `*.spec.tsx` | Unit and integration tests | `test` |
|
||||
|
||||
### Edge Patterns to Look For
|
||||
|
||||
**Component composition** — When a parent component renders a child component in its JSX return, create `contains` edges from the parent to the child. These edges represent the component tree hierarchy.
|
||||
|
||||
**Hook usage** — When a component or hook imports and calls a custom hook (`useX`), create `depends_on` edges from the consumer to the hook module. Hooks are the primary mechanism for shared logic in React.
|
||||
|
||||
**Context provider/consumer** — When a Context provider wraps components, create `publishes` edges from the provider to the context definition. When components call `useContext` or use a custom context hook, create `subscribes` edges from the consumer to the context.
|
||||
|
||||
**Props drilling chains** — When props are passed through multiple component layers without being used, create `depends_on` edges along the chain to surface the coupling depth.
|
||||
|
||||
### Architectural Layers for React
|
||||
|
||||
Assign nodes to these layers when detected:
|
||||
|
||||
| Layer ID | Layer Name | What Goes Here |
|
||||
|---|---|---|
|
||||
| `layer:ui` | UI Layer | `components/`, `pages/`, `views/`, layout components |
|
||||
| `layer:service` | Service Layer | `hooks/`, `contexts/`, `services/`, `api/`, `store/` |
|
||||
| `layer:types` | Types Layer | `types/`, shared TypeScript interfaces and type definitions |
|
||||
| `layer:utility` | Utility Layer | `utils/`, `helpers/`, pure functions |
|
||||
| `layer:config` | Config Layer | `App.tsx`, router configuration, provider setup, constants |
|
||||
| `layer:test` | Test Layer | `__tests__/`, `*.test.tsx`, `*.spec.tsx` |
|
||||
|
||||
### Notable Patterns to Capture in languageLesson
|
||||
|
||||
- **Component composition over inheritance**: React favors composing components via props and children rather than class inheritance hierarchies
|
||||
- **Custom hooks for reusable logic**: Hooks prefixed with `use` extract stateful logic into shareable modules without changing the component tree
|
||||
- **React.memo for performance**: Components wrapped in `React.memo` skip re-renders when props are unchanged — indicates performance-sensitive paths
|
||||
- **Controlled vs. uncontrolled components**: Controlled components derive state from props; uncontrolled components manage internal state via refs
|
||||
- **Render props pattern**: Components that accept a function as children or a render prop to delegate rendering decisions to the consumer
|
||||
@@ -0,0 +1,59 @@
|
||||
# Spring Boot Framework Addendum
|
||||
|
||||
> Injected into file-analyzer and architecture-analyzer prompts when Spring Boot is detected.
|
||||
> Do NOT use as a standalone prompt — always appended to the base prompt template.
|
||||
|
||||
## Spring Boot Project Structure
|
||||
|
||||
When analyzing a Spring Boot project, apply these additional conventions on top of the base analysis rules.
|
||||
|
||||
### Canonical File Roles
|
||||
|
||||
| File / Pattern | Role | Tags |
|
||||
|---|---|---|
|
||||
| `*Application.java`, `*Application.kt` | Application entry point — `@SpringBootApplication` class with `main()` method | `entry-point`, `config` |
|
||||
| `*Controller.java`, `*RestController.java` | REST controllers — handle HTTP requests, delegate to services | `api-handler` |
|
||||
| `*Service.java` | Service interfaces — define business operation contracts | `service` |
|
||||
| `*ServiceImpl.java` | Service implementations — contain business logic | `service` |
|
||||
| `*Repository.java` | Spring Data repositories — data access interfaces extending JpaRepository/CrudRepository | `data-model` |
|
||||
| `*Entity.java` | JPA entities — map to database tables via `@Entity` annotation | `data-model` |
|
||||
| `*DTO.java`, `*Request.java`, `*Response.java` | Data transfer objects — request/response payloads | `type-definition` |
|
||||
| `*Config.java`, `*Configuration.java` | Configuration classes — `@Configuration` beans, security config, web config | `config` |
|
||||
| `*Filter.java` | Servlet filters — intercept requests before they reach controllers | `middleware` |
|
||||
| `*Interceptor.java` | Handler interceptors — pre/post processing around controller methods | `middleware` |
|
||||
| `*Advice.java`, `*ExceptionHandler.java` | Controller advice — global exception handling and response wrapping | `middleware` |
|
||||
| `*Mapper.java` | Object mappers — convert between entities and DTOs (MapStruct, ModelMapper) | `utility` |
|
||||
| `application.yml`, `application.properties` | Application configuration — profiles, datasource, server settings | `config` |
|
||||
| `*Test.java`, `*Tests.java`, `*IT.java` | Unit tests, integration tests | `test` |
|
||||
|
||||
### Edge Patterns to Look For
|
||||
|
||||
**@Autowired injection** — When a class injects a dependency via `@Autowired`, constructor injection, or `@Inject`, create `depends_on` edges from the consumer to the injected bean. Constructor injection is preferred and most common in modern Spring.
|
||||
|
||||
**Controller-Service-Repository chain** — The canonical call chain is `@RestController` -> `@Service` -> `@Repository`. Create `depends_on` edges along this chain to show the layered architecture.
|
||||
|
||||
**@Entity relationships** — When entities define `@OneToMany`, `@ManyToOne`, `@OneToOne`, or `@ManyToMany` annotations, create `depends_on` edges between entity classes with descriptions indicating the relationship type and direction.
|
||||
|
||||
**@Configuration bean definitions** — When a `@Configuration` class defines `@Bean` methods, create `configures` edges from the configuration class to the types it produces. These beans become available for injection throughout the application.
|
||||
|
||||
### Architectural Layers for Spring Boot
|
||||
|
||||
Assign nodes to these layers when detected:
|
||||
|
||||
| Layer ID | Layer Name | What Goes Here |
|
||||
|---|---|---|
|
||||
| `layer:api` | API Layer | `*Controller.java`, REST endpoints, API documentation |
|
||||
| `layer:service` | Service Layer | `*Service.java`, `*ServiceImpl.java`, business logic |
|
||||
| `layer:data` | Data Layer | `*Repository.java`, `*Entity.java`, JPA mappings, database migrations |
|
||||
| `layer:types` | Types Layer | `*DTO.java`, `*Request.java`, `*Response.java`, shared value objects |
|
||||
| `layer:config` | Config Layer | `*Configuration.java`, `application.yml`, security config, `*Application.java` |
|
||||
| `layer:middleware` | Middleware Layer | `*Filter.java`, `*Interceptor.java`, `*Advice.java`, security filters |
|
||||
| `layer:test` | Test Layer | `*Test.java`, `*Tests.java`, `*IT.java`, test configuration |
|
||||
|
||||
### Notable Patterns to Capture in languageLesson
|
||||
|
||||
- **Dependency injection via constructor injection**: Spring favors constructor injection over field injection (`@Autowired` on fields) — it makes dependencies explicit, supports immutability, and simplifies testing
|
||||
- **Layered architecture (Controller -> Service -> Repository)**: Spring Boot applications follow a strict layered pattern where controllers handle HTTP, services contain business logic, and repositories manage persistence
|
||||
- **Spring Security filter chain**: Security is implemented as a chain of servlet filters — `SecurityFilterChain` beans configure authentication, authorization, CORS, and CSRF protection
|
||||
- **JPA entity lifecycle**: Entities transition through states (transient, managed, detached, removed) — understanding this lifecycle is essential for tracing data flow through the persistence layer
|
||||
- **AOP for cross-cutting concerns**: `@Aspect` classes with `@Before`, `@After`, and `@Around` advice inject behavior at join points — used for logging, transactions (`@Transactional`), and caching (`@Cacheable`)
|
||||
@@ -0,0 +1,59 @@
|
||||
# Vue Framework Addendum
|
||||
|
||||
> Injected into file-analyzer and architecture-analyzer prompts when Vue is detected.
|
||||
> Do NOT use as a standalone prompt — always appended to the base prompt template.
|
||||
|
||||
## Vue Project Structure
|
||||
|
||||
When analyzing a Vue project, apply these additional conventions on top of the base analysis rules.
|
||||
|
||||
### Canonical File Roles
|
||||
|
||||
| File / Pattern | Role | Tags |
|
||||
|---|---|---|
|
||||
| `src/App.vue` | Root application component — mounts the top-level layout and router view | `entry-point`, `ui` |
|
||||
| `src/main.ts`, `src/main.js` | Application bootstrap — creates Vue app instance, registers plugins, mounts to DOM | `entry-point`, `config` |
|
||||
| `components/*.vue`, `components/**/*.vue` | Reusable UI components | `ui` |
|
||||
| `views/*.vue`, `pages/*.vue` | Page-level components mapped to routes | `ui`, `routing` |
|
||||
| `composables/*.ts`, `composables/*.js` | Composable functions — reusable stateful logic using Composition API | `service`, `utility` |
|
||||
| `store/*.ts`, `stores/*.ts` | State management modules (Pinia stores or Vuex modules) | `service`, `state` |
|
||||
| `router/*.ts`, `router/index.ts` | Vue Router configuration — route definitions, navigation guards | `config`, `routing` |
|
||||
| `plugins/*.ts`, `plugins/*.js` | Vue plugin registrations — extend app functionality (i18n, auth, etc.) | `config` |
|
||||
| `utils/*.ts`, `helpers/*.ts` | Pure utility functions | `utility` |
|
||||
| `types/*.ts`, `types/*.d.ts` | TypeScript type definitions and interfaces | `type-definition` |
|
||||
| `api/*.ts`, `services/*.ts` | API client functions and data-fetching logic | `service` |
|
||||
| `directives/*.ts` | Custom Vue directives | `utility` |
|
||||
| `tests/*.spec.ts`, `__tests__/*.spec.ts` | Unit and integration tests | `test` |
|
||||
|
||||
### Edge Patterns to Look For
|
||||
|
||||
**Component parent-child** — When a parent component uses a child component in its `<template>`, create `contains` edges from the parent to the child. Template refs and slot usage further indicate composition relationships.
|
||||
|
||||
**Composable usage** — When a component or composable imports and calls a `useX` function, create `depends_on` edges from the consumer to the composable module. Composables are the primary mechanism for shared stateful logic.
|
||||
|
||||
**Store actions/getters** — When components or composables import and use a Pinia store (`useXStore()`), create `depends_on` edges from the consumer to the store. Store-to-store dependencies should also be captured.
|
||||
|
||||
**Router view mapping** — When `router/index.ts` maps paths to view components, create `configures` edges from the router to each view component. Navigation guards add middleware-like edges.
|
||||
|
||||
**Plugin registration** — When `main.ts` calls `app.use(plugin)`, create `configures` edges from the bootstrap file to each plugin.
|
||||
|
||||
### Architectural Layers for Vue
|
||||
|
||||
Assign nodes to these layers when detected:
|
||||
|
||||
| Layer ID | Layer Name | What Goes Here |
|
||||
|---|---|---|
|
||||
| `layer:ui` | UI Layer | `components/`, `views/`, `pages/`, layout components |
|
||||
| `layer:service` | Service Layer | `composables/`, `store/`, `stores/`, `api/`, `services/` |
|
||||
| `layer:config` | Config Layer | `router/`, `plugins/`, `main.ts`, `App.vue`, configuration files |
|
||||
| `layer:utility` | Utility Layer | `utils/`, `helpers/`, `directives/`, pure functions |
|
||||
| `layer:test` | Test Layer | `tests/`, `__tests__/`, `*.spec.ts` |
|
||||
|
||||
### Notable Patterns to Capture in languageLesson
|
||||
|
||||
- **Composition API over Options API**: Modern Vue favors `setup()` and `<script setup>` with composables, replacing the Options API's data/methods/computed separation
|
||||
- **Pinia for state management**: Pinia stores provide type-safe, modular state with actions and getters — each store is independently defined and can depend on other stores
|
||||
- **Vue Router with navigation guards**: `beforeEach`, `beforeEnter`, and `afterEach` guards act as middleware for route transitions — used for authentication and data prefetching
|
||||
- **Single-file components (.vue)**: Each `.vue` file encapsulates template, script, and style in a single file — the `<script setup>` syntax is the recommended concise form
|
||||
- **Reactive refs and computed properties**: `ref()` and `reactive()` create reactive state; `computed()` derives values that auto-update — understanding reactivity is key to tracing data flow
|
||||
- **Provide/inject for deep dependency passing**: `provide()` and `inject()` pass values down the component tree without prop drilling — creates implicit dependencies that should be captured as edges
|
||||
@@ -0,0 +1,47 @@
|
||||
# C++ Language Prompt Snippet
|
||||
|
||||
## Key Concepts
|
||||
|
||||
- **Templates**: Function, class, and variadic templates for generic compile-time polymorphism
|
||||
- **RAII**: Resource Acquisition Is Initialization — tie resource lifetime to object scope
|
||||
- **Smart Pointers**: `unique_ptr` (exclusive), `shared_ptr` (reference-counted), `weak_ptr` (non-owning)
|
||||
- **Move Semantics**: Rvalue references (`&&`) and `std::move` for efficient resource transfer
|
||||
- **Operator Overloading**: Define custom behavior for operators on user-defined types
|
||||
- **Virtual Functions and Vtable**: Runtime polymorphism through virtual method dispatch tables
|
||||
- **Namespaces**: Organize symbols and prevent name collisions across translation units
|
||||
- **Constexpr**: Compile-time evaluation of functions and variables for zero-runtime-cost computation
|
||||
- **Lambda Expressions**: Anonymous functions with capture lists for closures
|
||||
- **STL Containers and Algorithms**: Standard containers (vector, map, set) and generic algorithms
|
||||
- **Concepts (C++20)**: Named constraints on template parameters replacing SFINAE patterns
|
||||
|
||||
## Import Patterns
|
||||
|
||||
- `#include <system_header>` — include standard library or system headers
|
||||
- `#include "local_header.h"` — include project-local header files
|
||||
- `using namespace std` — bring all names from std into scope (avoid in headers)
|
||||
- `using std::vector` — selectively bring specific names into scope
|
||||
|
||||
## File Patterns
|
||||
|
||||
- `.h` / `.hpp` — header files containing declarations, templates, and inline definitions
|
||||
- `.cpp` / `.cc` — implementation files with function definitions and static data
|
||||
- `CMakeLists.txt` — CMake build system configuration
|
||||
- `Makefile` — Make-based build rules and targets
|
||||
- `main.cpp` — program entry point containing `int main()`
|
||||
|
||||
## Common Frameworks
|
||||
|
||||
- **Qt** — Cross-platform application framework with signal/slot mechanism
|
||||
- **Boost** — Extensive collection of peer-reviewed portable libraries
|
||||
- **Catch2** — Header-only testing framework with BDD-style syntax
|
||||
- **Google Test** — Testing framework with fixtures, assertions, and mocking
|
||||
- **gRPC** — High-performance RPC framework for service communication
|
||||
|
||||
## Example Language Notes
|
||||
|
||||
> Uses `std::unique_ptr<T>` for RAII-based ownership, ensuring deterministic cleanup
|
||||
> when scope exits. The unique pointer cannot be copied, only moved, making ownership
|
||||
> transfer explicit and preventing accidental double-free errors.
|
||||
>
|
||||
> Header/implementation separation (`.h`/`.cpp`) controls compilation boundaries —
|
||||
> changes to a `.cpp` file only recompile that translation unit, not all includers.
|
||||
@@ -0,0 +1,46 @@
|
||||
# C# Language Prompt Snippet
|
||||
|
||||
## Key Concepts
|
||||
|
||||
- **LINQ Queries**: Language-integrated queries using method syntax (`.Where().Select()`) or query syntax
|
||||
- **Async/Await with Task**: Asynchronous programming model returning `Task<T>` for non-blocking I/O
|
||||
- **Generics and Constraints**: Type parameters with `where T : class, IDisposable` constraint clauses
|
||||
- **Properties (get/set)**: First-class property syntax with backing fields, auto-properties, and init-only
|
||||
- **Delegates and Events**: Type-safe function pointers; events provide publisher-subscriber pattern
|
||||
- **Attributes**: Metadata annotations (`[HttpGet]`, `[Authorize]`) for declarative configuration
|
||||
- **Nullable Reference Types**: Compiler-enforced null safety with `?` annotations (C# 8+)
|
||||
- **Pattern Matching**: `is`, `switch` expressions with type, property, and relational patterns
|
||||
- **Records and Init-Only Setters**: Immutable reference types with value equality semantics (C# 9+)
|
||||
- **Dependency Injection (Built-in)**: First-class DI container in ASP.NET Core (`IServiceCollection`)
|
||||
|
||||
## Import Patterns
|
||||
|
||||
- `using System.Collections.Generic` — import a namespace for unqualified type access
|
||||
- `using static System.Math` — import static members for direct method access
|
||||
- `global using` — file-scoped usings applied to the entire project (C# 10)
|
||||
- `using Alias = Namespace.Type` — type alias for disambiguation
|
||||
|
||||
## File Patterns
|
||||
|
||||
- `*.csproj` — MSBuild project file defining targets, packages, and build properties
|
||||
- `*.sln` — Visual Studio solution file grouping multiple projects
|
||||
- `Program.cs` — application entry point (top-level statements in .NET 6+)
|
||||
- `Startup.cs` — service and middleware configuration (older ASP.NET Core pattern)
|
||||
- `appsettings.json` — hierarchical application configuration
|
||||
|
||||
## Common Frameworks
|
||||
|
||||
- **ASP.NET Core** — Cross-platform web framework for APIs, MVC, and Razor Pages
|
||||
- **Entity Framework** — ORM with LINQ-to-SQL, migrations, and change tracking
|
||||
- **Blazor** — Component-based UI framework using C# instead of JavaScript
|
||||
- **MAUI** — Cross-platform native UI for mobile and desktop applications
|
||||
- **xUnit** — Modern testing framework with theories, facts, and dependency injection
|
||||
|
||||
## Example Language Notes
|
||||
|
||||
> Uses LINQ method syntax `.Where().Select()` to compose a query pipeline over the
|
||||
> collection. LINQ operations are lazily evaluated — the query only executes when
|
||||
> results are enumerated, allowing efficient composition without intermediate allocations.
|
||||
>
|
||||
> The built-in DI container in ASP.NET Core registers services in `Program.cs` and
|
||||
> resolves them via constructor injection, following the composition root pattern.
|
||||
@@ -0,0 +1,47 @@
|
||||
# Go Language Prompt Snippet
|
||||
|
||||
## Key Concepts
|
||||
|
||||
- **Goroutines**: Lightweight concurrent functions launched with `go` keyword
|
||||
- **Channels**: Typed conduits for communication and synchronization between goroutines
|
||||
- **Interfaces**: Implicitly satisfied contracts — no `implements` keyword needed
|
||||
- **Struct Embedding**: Composition mechanism providing field and method promotion
|
||||
- **Error Handling**: Explicit error return values (`error` interface) instead of exceptions
|
||||
- **Defer/Panic/Recover**: Deferred cleanup, unrecoverable errors, and recovery mechanism
|
||||
- **Slices vs Arrays**: Arrays are fixed-size values; slices are dynamic views backed by arrays
|
||||
- **Pointers**: Explicit pointer types for pass-by-reference semantics (no pointer arithmetic)
|
||||
- **Context Propagation**: `context.Context` carries deadlines, cancellation, and request-scoped values
|
||||
- **Init Functions**: Package-level `init()` runs automatically before `main()` for setup
|
||||
|
||||
## Import Patterns
|
||||
|
||||
- `import "package"` — single package import
|
||||
- `import alias "package"` — aliased import to avoid name conflicts
|
||||
- `import ( ... )` — grouped import block (standard library, then external, then internal)
|
||||
- `import _ "package"` — blank import for side effects only (e.g., driver registration)
|
||||
|
||||
## File Patterns
|
||||
|
||||
- `*_test.go` — test files in the same package (or `_test` package for black-box tests)
|
||||
- `cmd/` — directory containing main packages (binary entry points)
|
||||
- `internal/` — packages only importable by parent module (enforced by compiler)
|
||||
- `pkg/` — public library packages (convention, not enforced)
|
||||
- `go.mod` — module definition with dependency versions
|
||||
- `go.sum` — cryptographic checksums for dependencies
|
||||
|
||||
## Common Frameworks
|
||||
|
||||
- **Gin** — High-performance HTTP framework with middleware support
|
||||
- **Echo** — Minimalist web framework with built-in middleware
|
||||
- **Fiber** — Express-inspired framework built on fasthttp
|
||||
- **Chi** — Lightweight, composable HTTP router
|
||||
- **GORM** — ORM library with associations, hooks, and migrations
|
||||
|
||||
## Example Language Notes
|
||||
|
||||
> Implements `io.Reader` interface implicitly — no explicit declaration needed, just
|
||||
> matching method signatures. This enables any type with a `Read([]byte) (int, error)`
|
||||
> method to be used wherever `io.Reader` is expected.
|
||||
>
|
||||
> The `internal/` directory enforces encapsulation at the compiler level, preventing
|
||||
> external packages from importing implementation details — stronger than naming convention.
|
||||
@@ -0,0 +1,45 @@
|
||||
# Java Language Prompt Snippet
|
||||
|
||||
## Key Concepts
|
||||
|
||||
- **Generics (with Erasure)**: Parameterized types erased at runtime; compile-time safety only
|
||||
- **Annotations**: Metadata markers (`@Override`, `@Autowired`) processed at compile or runtime
|
||||
- **Interfaces and Abstract Classes**: Contracts with default methods (Java 8+) and partial implementations
|
||||
- **Streams API**: Functional-style pipeline operations on collections (filter, map, reduce)
|
||||
- **Lambdas**: Concise anonymous function syntax for functional interfaces
|
||||
- **Sealed Classes**: Restricted class hierarchies with explicit permitted subclasses (Java 17+)
|
||||
- **Records**: Immutable data carriers with auto-generated accessors, equals, hashCode (Java 16+)
|
||||
- **Dependency Injection**: IoC pattern central to Spring; constructor, field, or method injection
|
||||
- **Checked vs Unchecked Exceptions**: Checked must be declared or caught; unchecked extend RuntimeException
|
||||
- **Optional**: Container for nullable values encouraging explicit handling over null checks
|
||||
|
||||
## Import Patterns
|
||||
|
||||
- `import package.Class` — import a specific class
|
||||
- `import package.*` — wildcard import of all classes in a package
|
||||
- `import static package.Class.method` — static import for direct method/constant access
|
||||
|
||||
## File Patterns
|
||||
|
||||
- `src/main/java/` — source root following Maven/Gradle standard layout
|
||||
- `src/test/java/` — test source root with matching package structure
|
||||
- `pom.xml` — Maven project configuration and dependency management
|
||||
- `build.gradle` — Gradle build script (Groovy or Kotlin DSL)
|
||||
- `Application.java` — Spring Boot entry point with `@SpringBootApplication`
|
||||
|
||||
## Common Frameworks
|
||||
|
||||
- **Spring Boot** — Opinionated framework for production-ready Spring applications
|
||||
- **Jakarta EE** — Enterprise Java standards (formerly Java EE) for server-side development
|
||||
- **Quarkus** — Cloud-native framework optimized for GraalVM and containers
|
||||
- **Micronaut** — Compile-time DI framework for microservices and serverless
|
||||
- **Hibernate** — ORM framework implementing JPA specification
|
||||
|
||||
## Example Language Notes
|
||||
|
||||
> Uses `@Autowired` annotation for constructor injection, following Spring IoC container
|
||||
> pattern. Constructor injection is preferred over field injection because it makes
|
||||
> dependencies explicit and enables immutability.
|
||||
>
|
||||
> The Maven standard directory layout (`src/main/java`, `src/test/java`) is a strong
|
||||
> convention — most build tools and IDEs expect this structure by default.
|
||||
@@ -0,0 +1,46 @@
|
||||
# JavaScript Language Prompt Snippet
|
||||
|
||||
## Key Concepts
|
||||
|
||||
- **Closures**: Functions that capture variables from their enclosing lexical scope
|
||||
- **Prototypes**: Prototype chain-based inheritance underlying all JavaScript objects
|
||||
- **Promises**: Asynchronous value containers enabling `.then()` chaining and `async/await`
|
||||
- **Event Loop**: Single-threaded concurrency model with microtask and macrotask queues
|
||||
- **Destructuring**: Extract values from objects and arrays into distinct variables
|
||||
- **Spread/Rest Operators**: `...` for expanding iterables or collecting remaining arguments
|
||||
- **Proxies**: Meta-programming construct to intercept and customize object operations
|
||||
- **Generators**: Functions using `function*` and `yield` for lazy iteration
|
||||
- **Symbol**: Unique, immutable primitive used for non-string property keys
|
||||
- **WeakMap/WeakSet**: Collections with weakly-held keys allowing garbage collection
|
||||
- **Modules (ESM vs CJS)**: ES Modules use `import/export`; CommonJS uses `require/module.exports`
|
||||
|
||||
## Import Patterns
|
||||
|
||||
- `import { X } from 'module'` — ESM named import
|
||||
- `const X = require('module')` — CommonJS require
|
||||
- `import('module')` — dynamic import returning a Promise (code splitting)
|
||||
- `export default X` / `export { X }` — ESM export forms
|
||||
|
||||
## File Patterns
|
||||
|
||||
- `index.js` — barrel file or directory entry point
|
||||
- `.mjs` — explicitly ES Module files
|
||||
- `.cjs` — explicitly CommonJS files
|
||||
- `package.json` `"type"` field — sets default module system (`"module"` or `"commonjs"`)
|
||||
|
||||
## Common Frameworks
|
||||
|
||||
- **React** — Declarative UI with virtual DOM and component model
|
||||
- **Vue** — Progressive framework with reactivity system and single-file components
|
||||
- **Express** — Minimal and flexible Node.js web application framework
|
||||
- **Next.js** — React framework for production with hybrid rendering
|
||||
- **Svelte** — Compile-time framework that shifts work from runtime to build step
|
||||
|
||||
## Example Language Notes
|
||||
|
||||
> Closure captures outer `config` variable, providing encapsulated state without class
|
||||
> overhead. The returned object's methods share access to the same `config` reference,
|
||||
> forming a module pattern that was standard before ES Modules.
|
||||
>
|
||||
> When encountering `.mjs` vs `.cjs` extensions, the module system is determined by
|
||||
> extension regardless of the `package.json` type field — useful in mixed codebases.
|
||||
@@ -0,0 +1,45 @@
|
||||
# Kotlin Language Prompt Snippet
|
||||
|
||||
## Key Concepts
|
||||
|
||||
- **Coroutines and Flow**: Structured concurrency with suspending functions; Flow for reactive streams
|
||||
- **Data Classes**: Auto-generated `equals`, `hashCode`, `toString`, `copy`, and destructuring
|
||||
- **Sealed Classes/Interfaces**: Restricted hierarchies enabling exhaustive `when` expressions
|
||||
- **Extension Functions**: Add methods to existing classes without inheritance or wrappers
|
||||
- **Null Safety**: `?.` safe call, `!!` non-null assertion, `?:` Elvis operator for default values
|
||||
- **Delegation (by keyword)**: Delegate interface implementation or property access to another object
|
||||
- **DSL Builders**: Lambda-with-receiver syntax enabling type-safe builder patterns
|
||||
- **Inline Functions and Reified Types**: Inline for zero-overhead lambdas; reified for runtime type access
|
||||
- **Companion Objects**: Named or anonymous singleton associated with a class (replaces static members)
|
||||
- **Scope Functions**: `let`, `run`, `apply`, `also`, `with` for concise object configuration and transformation
|
||||
|
||||
## Import Patterns
|
||||
|
||||
- `import package.ClassName` — import a specific class
|
||||
- `import package.*` — wildcard import of all declarations in a package
|
||||
- `import package.function as alias` — import with alias to resolve naming conflicts
|
||||
|
||||
## File Patterns
|
||||
|
||||
- `build.gradle.kts` — Gradle build script using Kotlin DSL
|
||||
- `Application.kt` — application entry point (Spring Boot or Ktor)
|
||||
- `src/main/kotlin/` — main source root following Gradle conventions
|
||||
- `src/test/kotlin/` — test source root with matching package structure
|
||||
- `settings.gradle.kts` — multi-module project configuration
|
||||
|
||||
## Common Frameworks
|
||||
|
||||
- **Spring Boot (Kotlin)** — Kotlin-first support with coroutines and DSL extensions
|
||||
- **Ktor** — Kotlin-native async web framework from JetBrains
|
||||
- **Jetpack Compose** — Declarative UI toolkit for Android using composable functions
|
||||
- **Exposed** — Lightweight SQL framework with type-safe DSL and DAO patterns
|
||||
- **Koin** — Pragmatic dependency injection framework using Kotlin DSL
|
||||
|
||||
## Example Language Notes
|
||||
|
||||
> Uses sealed class hierarchy with `when` exhaustive matching to handle all possible
|
||||
> API response states. The compiler enforces that every variant is covered, eliminating
|
||||
> the need for a fallback `else` branch and catching missing cases at compile time.
|
||||
>
|
||||
> Extension functions allow adding utilities like `String.toSlug()` without modifying
|
||||
> the original class — keeping the extension discoverable through IDE auto-complete.
|
||||
@@ -0,0 +1,46 @@
|
||||
# PHP Language Prompt Snippet
|
||||
|
||||
## Key Concepts
|
||||
|
||||
- **Namespaces**: Organize code and prevent naming collisions using backslash-delimited paths
|
||||
- **Traits**: Horizontal code reuse mechanism for sharing methods across unrelated classes
|
||||
- **Type Declarations**: Parameter, return, and property types (scalar, union, intersection types)
|
||||
- **Attributes (PHP 8+)**: Native metadata annotations replacing docblock-based configuration
|
||||
- **Enums (PHP 8.1+)**: First-class enumeration types with methods and interface implementation
|
||||
- **Fibers**: Lightweight cooperative concurrency primitives for non-blocking I/O
|
||||
- **Closures/Anonymous Functions**: First-class functions with explicit `use` for variable capture
|
||||
- **Magic Methods**: Special methods like `__construct`, `__get`, `__set`, `__call` for object behavior
|
||||
- **Dependency Injection**: Constructor injection managed by PSR-11 compatible containers
|
||||
- **Middleware**: Request/response pipeline pattern central to modern PHP frameworks
|
||||
|
||||
## Import Patterns
|
||||
|
||||
- `use Namespace\ClassName` — import a class by its fully qualified name
|
||||
- `use Namespace\ClassName as Alias` — import with an alias to avoid conflicts
|
||||
- `namespace App\Http\Controllers` — declare the current file's namespace
|
||||
- `use function Namespace\functionName` — import a namespaced function
|
||||
|
||||
## File Patterns
|
||||
|
||||
- `composer.json` — dependency management and PSR-4 autoloading configuration
|
||||
- `index.php` — web application entry point (front controller)
|
||||
- `artisan` — Laravel CLI entry point for commands and migrations
|
||||
- `routes/` — route definition files (web.php, api.php in Laravel)
|
||||
- PSR-4 autoloading maps namespace prefixes to directory paths
|
||||
|
||||
## Common Frameworks
|
||||
|
||||
- **Laravel** — Full-featured framework with Eloquent ORM, Blade templates, and queues
|
||||
- **Symfony** — Component-based framework powering many PHP projects and libraries
|
||||
- **WordPress** — CMS platform with hook-based plugin architecture
|
||||
- **Slim** — Micro-framework for APIs and small applications
|
||||
- **CodeIgniter** — Lightweight MVC framework with minimal configuration
|
||||
|
||||
## Example Language Notes
|
||||
|
||||
> Uses PHP 8 attributes `#[Route('/api/users')]` for declarative route mapping on
|
||||
> controller methods. Attributes replace the older docblock annotation pattern,
|
||||
> providing native language support for metadata that tools can reflect upon.
|
||||
>
|
||||
> PSR-4 autoloading in `composer.json` maps `App\` to `src/`, so the class
|
||||
> `App\Http\Controllers\UserController` loads from `src/Http/Controllers/UserController.php`.
|
||||
@@ -0,0 +1,48 @@
|
||||
# Python Language Prompt Snippet
|
||||
|
||||
## Key Concepts
|
||||
|
||||
- **Decorators**: Functions that wrap other functions or classes using `@decorator` syntax
|
||||
- **List/Dict Comprehensions**: Concise syntax for creating collections from iterables
|
||||
- **Generators and Yield**: Lazy iterators using `yield` for memory-efficient data processing
|
||||
- **Context Managers**: `with` statement for resource management via `__enter__`/`__exit__`
|
||||
- **Type Hints and Typing Module**: Optional static type annotations for tooling and documentation
|
||||
- **Dunder Methods**: Special methods like `__init__`, `__repr__`, `__eq__` defining object behavior
|
||||
- **Metaclasses**: Classes that define how other classes are created (type as default metaclass)
|
||||
- **Dataclasses**: `@dataclass` decorator auto-generating boilerplate from field annotations
|
||||
- **Protocols**: Structural subtyping via `typing.Protocol` for duck-type-safe interfaces
|
||||
- **Descriptors**: Objects defining `__get__`, `__set__`, `__delete__` to customize attribute access
|
||||
- **Async/Await with Asyncio**: Cooperative concurrency using coroutines and an event loop
|
||||
|
||||
## Import Patterns
|
||||
|
||||
- `from module import name` — import specific name from module
|
||||
- `import module` — import entire module, access via `module.name`
|
||||
- `from package.module import name` — absolute import from nested package
|
||||
- `from . import relative` — relative import within a package
|
||||
|
||||
## File Patterns
|
||||
|
||||
- `__init__.py` — package initializer (barrel equivalent), can re-export public API
|
||||
- `__main__.py` — package entry point when run with `python -m package`
|
||||
- `conftest.py` — pytest shared fixtures and hooks (auto-discovered)
|
||||
- `setup.py` / `pyproject.toml` — project configuration and build metadata
|
||||
- `requirements.txt` — pinned dependency list
|
||||
|
||||
## Common Frameworks
|
||||
|
||||
- **Django** — Full-stack web framework with ORM, admin, and batteries included
|
||||
- **FastAPI** — Modern async API framework with automatic OpenAPI docs
|
||||
- **Flask** — Lightweight WSGI micro-framework for web applications
|
||||
- **SQLAlchemy** — SQL toolkit and ORM with unit-of-work pattern
|
||||
- **Celery** — Distributed task queue for background job processing
|
||||
- **Pydantic** — Data validation and settings management using type annotations
|
||||
|
||||
## Example Language Notes
|
||||
|
||||
> Uses `@dataclass` decorator to auto-generate `__init__`, `__repr__`, and `__eq__` from
|
||||
> field annotations. This eliminates boilerplate while keeping the class definition
|
||||
> readable and the generated methods consistent.
|
||||
>
|
||||
> When `__init__.py` re-exports symbols, it acts as the package's public API surface —
|
||||
> consumers import from the package rather than reaching into internal modules.
|
||||
@@ -0,0 +1,46 @@
|
||||
# Ruby Language Prompt Snippet
|
||||
|
||||
## Key Concepts
|
||||
|
||||
- **Blocks/Procs/Lambdas**: First-class callable objects; blocks are implicit, procs and lambdas are explicit
|
||||
- **Mixins (include/extend)**: Share behavior across classes via modules without inheritance
|
||||
- **Metaprogramming**: Dynamic method definition (`define_method`), interception (`method_missing`)
|
||||
- **Duck Typing**: Objects are defined by what they can do, not what class they are
|
||||
- **DSLs**: Domain-specific languages built using blocks and metaprogramming (e.g., Rails routes)
|
||||
- **Monkey Patching**: Reopening existing classes to add or modify methods at runtime
|
||||
- **Symbols**: Immutable, interned strings (`:name`) used as identifiers and hash keys
|
||||
- **Open Classes**: Any class can be reopened and extended at any point in the program
|
||||
- **Enumerable Module**: Mixin providing collection methods (map, select, reduce) to any class with `each`
|
||||
|
||||
## Import Patterns
|
||||
|
||||
- `require 'gem_name'` — load a gem or standard library module
|
||||
- `require_relative './file'` — load a file relative to the current file's directory
|
||||
- `load 'file.rb'` — load and re-execute a file (unlike require, does not cache)
|
||||
- `autoload :ClassName, 'path'` — lazy loading of constants on first reference
|
||||
|
||||
## File Patterns
|
||||
|
||||
- `Gemfile` — dependency declarations managed by Bundler
|
||||
- `Rakefile` — task definitions (Ruby's make equivalent)
|
||||
- `spec/` — RSpec test directory with `*_spec.rb` convention
|
||||
- `test/` — Minitest directory with `test_*.rb` or `*_test.rb` convention
|
||||
- `config.ru` — Rack application entry point for web servers
|
||||
- `lib/` — main source code directory by convention
|
||||
|
||||
## Common Frameworks
|
||||
|
||||
- **Rails** — Full-stack web framework following convention over configuration
|
||||
- **Sinatra** — Minimal DSL for creating web applications quickly
|
||||
- **RSpec** — Behavior-driven testing framework with expressive DSL
|
||||
- **Sidekiq** — Background job processing using Redis-backed queues
|
||||
- **Grape** — REST API micro-framework for Ruby
|
||||
|
||||
## Example Language Notes
|
||||
|
||||
> Uses `method_missing` to dynamically delegate attribute access to the wrapped model
|
||||
> object. When a method is not found on the decorator, it falls through to the model,
|
||||
> providing transparent delegation without explicit forwarding methods.
|
||||
>
|
||||
> Rails relies heavily on convention over configuration — file placement in `app/models/`,
|
||||
> `app/controllers/`, etc. determines behavior without explicit registration.
|
||||
@@ -0,0 +1,47 @@
|
||||
# Rust Language Prompt Snippet
|
||||
|
||||
## Key Concepts
|
||||
|
||||
- **Ownership and Borrowing**: Each value has one owner; references borrow without taking ownership
|
||||
- **Lifetimes**: Annotations (`'a`) ensuring references remain valid for their required duration
|
||||
- **Traits and Trait Objects**: Shared behavior definitions; `dyn Trait` for dynamic dispatch
|
||||
- **Pattern Matching**: Exhaustive `match` expressions deconstructing enums, structs, and tuples
|
||||
- **Enums with Data**: Algebraic data types — each variant can carry different associated data
|
||||
- **Result/Option Error Handling**: `Result<T, E>` for fallible ops; `Option<T>` for nullable values
|
||||
- **Macros**: Declarative (`macro_rules!`) and procedural (derive, attribute, function-like) code generation
|
||||
- **Async/Await with Tokio**: Zero-cost async using `Future` trait and runtime executors
|
||||
- **Unsafe Blocks**: Opt-in blocks for raw pointer dereferencing, FFI, and bypassing borrow checker
|
||||
- **Generics with Trait Bounds**: `<T: Clone + Send>` constraining generic parameters
|
||||
- **Closures and Fn Traits**: `Fn`, `FnMut`, `FnOnce` determine how closures capture environment
|
||||
|
||||
## Import Patterns
|
||||
|
||||
- `use crate::module::Item` — import from current crate
|
||||
- `use std::collections::HashMap` — import from standard library
|
||||
- `use super::*` — import everything from parent module
|
||||
- `mod module_name` — declare a submodule (loads from file)
|
||||
|
||||
## File Patterns
|
||||
|
||||
- `mod.rs` — module barrel file (older convention) or `module_name.rs` (2018+ edition)
|
||||
- `lib.rs` — library crate root defining the public API
|
||||
- `main.rs` — binary crate entry point
|
||||
- `Cargo.toml` — project manifest with dependencies and metadata
|
||||
- `build.rs` — build script executed before compilation
|
||||
|
||||
## Common Frameworks
|
||||
|
||||
- **Actix-web** — Actor-based, high-performance web framework
|
||||
- **Axum** — Ergonomic web framework built on Tower and Hyper
|
||||
- **Rocket** — Type-safe web framework with declarative routing
|
||||
- **Diesel** — Safe, composable ORM and query builder
|
||||
- **Tokio** — Async runtime providing I/O, timers, and task scheduling
|
||||
|
||||
## Example Language Notes
|
||||
|
||||
> Takes `&self` borrow to read state without transferring ownership; returns
|
||||
> `Result<T, Error>` for explicit error propagation. The `?` operator propagates
|
||||
> errors up the call stack concisely, replacing verbose match blocks.
|
||||
>
|
||||
> The module system maps to the filesystem: `mod handlers;` loads either
|
||||
> `handlers.rs` or `handlers/mod.rs`, establishing the module tree at compile time.
|
||||
@@ -0,0 +1,46 @@
|
||||
# Swift Language Prompt Snippet
|
||||
|
||||
## Key Concepts
|
||||
|
||||
- **Optionals and Optional Chaining**: `Type?` wraps values that may be nil; `?.` chains safely
|
||||
- **Protocols and Protocol Extensions**: Define contracts with default implementations via extensions
|
||||
- **Value Types vs Reference Types**: Structs and enums are value types; classes are reference types
|
||||
- **Closures**: Self-contained blocks of functionality that capture surrounding context
|
||||
- **Property Wrappers**: `@State`, `@Binding`, `@Published` encapsulate property storage logic
|
||||
- **Result Builders**: `@ViewBuilder`, `@resultBuilder` enable declarative DSL syntax
|
||||
- **Actors and Structured Concurrency**: `actor` types for data isolation; `async let`, `TaskGroup`
|
||||
- **Generics**: Type parameters with `where` clauses and associated type constraints
|
||||
- **Enums with Associated Values**: Each case can carry distinct typed payloads
|
||||
- **Extensions**: Add methods, computed properties, and protocol conformance to existing types
|
||||
|
||||
## Import Patterns
|
||||
|
||||
- `import Foundation` — core library with data types, collections, networking
|
||||
- `import UIKit` — iOS UI framework for traditional view controller architecture
|
||||
- `import SwiftUI` — declarative UI framework with reactive state management
|
||||
- `@testable import ModuleName` — import with internal access for unit testing
|
||||
|
||||
## File Patterns
|
||||
|
||||
- `Package.swift` — Swift Package Manager manifest defining targets and dependencies
|
||||
- `*.xcodeproj` / `*.xcworkspace` — Xcode project and workspace configuration
|
||||
- `AppDelegate.swift` — UIKit application lifecycle entry point
|
||||
- `App.swift` — SwiftUI application entry point using `@main`
|
||||
- `Tests/` — test target directory following SPM or Xcode conventions
|
||||
|
||||
## Common Frameworks
|
||||
|
||||
- **SwiftUI** — Declarative UI framework with reactive data flow
|
||||
- **UIKit** — Imperative UI framework using view controllers and Auto Layout
|
||||
- **Vapor** — Server-side Swift web framework with async support
|
||||
- **Combine** — Reactive framework for processing values over time
|
||||
- **Core Data** — Object graph and persistence framework
|
||||
|
||||
## Example Language Notes
|
||||
|
||||
> Uses `@Published` property wrapper to automatically notify SwiftUI views of state
|
||||
> changes. When the wrapped value mutates, the property wrapper triggers `objectWillChange`
|
||||
> on the enclosing `ObservableObject`, causing dependent views to re-render.
|
||||
>
|
||||
> Protocol extensions provide default implementations, allowing types to conform by
|
||||
> simply declaring conformance — no method body needed if defaults suffice.
|
||||
@@ -0,0 +1,46 @@
|
||||
# TypeScript Language Prompt Snippet
|
||||
|
||||
## Key Concepts
|
||||
|
||||
- **Generics**: Parameterized types (`<T>`) enabling reusable, type-safe abstractions
|
||||
- **Type Guards**: Runtime checks that narrow types within conditional blocks (`is`, `in`, `typeof`, `instanceof`)
|
||||
- **Discriminated Unions**: Union types with a shared literal field used for exhaustive narrowing
|
||||
- **Utility Types**: Built-in mapped types like `Partial<T>`, `Pick<T, K>`, `Omit<T, K>`, `Record<K, V>`
|
||||
- **Interfaces vs Types**: Interfaces support declaration merging; type aliases support unions and mapped types
|
||||
- **Enums**: Numeric and string enums for named constant sets; prefer `as const` objects when possible
|
||||
- **Mapped Types**: Transform existing types property-by-property using `[K in keyof T]` syntax
|
||||
- **Conditional Types**: `T extends U ? X : Y` for type-level branching logic
|
||||
- **Template Literal Types**: String manipulation at the type level using backtick syntax
|
||||
- **Declaration Merging**: Interfaces with the same name merge their members automatically
|
||||
- **Module Augmentation**: Extending third-party module types via `declare module` blocks
|
||||
|
||||
## Import Patterns
|
||||
|
||||
- `import { X } from 'module'` — named import (most common)
|
||||
- `import type { X } from 'module'` — type-only import (erased at runtime)
|
||||
- `import * as X from 'module'` — namespace import
|
||||
- `import X from 'module'` — default import
|
||||
|
||||
## File Patterns
|
||||
|
||||
- `index.ts` — barrel file re-exporting public API from a directory
|
||||
- `*.d.ts` — type declaration files (ambient declarations, no runtime code)
|
||||
- `tsconfig.json` — TypeScript compiler configuration and project references
|
||||
- `*.tsx` — TypeScript files containing JSX (React components)
|
||||
|
||||
## Common Frameworks
|
||||
|
||||
- **React** — UI component library with hooks and JSX
|
||||
- **Angular** — Full-featured framework with decorators and dependency injection
|
||||
- **Next.js** — React meta-framework with SSR, SSG, and API routes
|
||||
- **NestJS** — Server-side framework inspired by Angular (decorators, modules, DI)
|
||||
- **Express (with TS)** — Minimal HTTP framework with typed request/response handlers
|
||||
|
||||
## Example Language Notes
|
||||
|
||||
> Uses generic type parameter `T extends BaseEntity` to ensure type safety across
|
||||
> repository methods. The constraint guarantees all entities share a common `id` field
|
||||
> while allowing specific entity types to flow through the data layer without casting.
|
||||
>
|
||||
> Barrel files (`index.ts`) re-export symbols so consumers import from the directory
|
||||
> rather than reaching into internal module paths — maintaining encapsulation.
|
||||
@@ -84,8 +84,10 @@ Read config files (if they exist) and extract framework information:
|
||||
- `requirements.txt` -- if present, confirms Python project; read line by line and match package names (strip version specifiers) against known Python frameworks: `django`, `djangorestframework`, `fastapi`, `flask`, `sqlalchemy`, `alembic`, `celery`, `pydantic`, `uvicorn`, `gunicorn`, `aiohttp`, `tornado`, `starlette`, `pytest`, `hypothesis`, `channels`
|
||||
- `pyproject.toml` -- if present, confirms Python project; parse the `[project].dependencies` or `[tool.poetry.dependencies]` section and apply the same Python framework keyword matching as above. Also check for `[tool.pytest.ini_options]` (confirms pytest) and `[tool.django]` (confirms Django).
|
||||
- `setup.py` / `setup.cfg` / `Pipfile` -- if present, confirms Python project; read and apply Python framework keyword matching
|
||||
- `Gemfile` -- if present, confirms Ruby project
|
||||
- `pom.xml` / `build.gradle` -- if present, confirms Java project
|
||||
- `Gemfile` -- if present, confirms Ruby project; read and match gem names against known Ruby frameworks: `rails`, `railties`, `sinatra`, `grape`, `rspec`, `sidekiq`, `activerecord`, `actionpack`, `devise`, `pundit`
|
||||
- `go.mod` dependencies -- if present, read the `require` block and match module paths against known Go frameworks: `github.com/gin-gonic/gin`, `github.com/labstack/echo`, `github.com/gofiber/fiber`, `github.com/go-chi/chi`, `gorm.io/gorm`
|
||||
- `Cargo.toml` dependencies -- if present, read `[dependencies]` and match crate names against known Rust frameworks: `actix-web`, `axum`, `rocket`, `diesel`, `tokio`, `serde`, `warp`
|
||||
- `pom.xml` / `build.gradle` / `build.gradle.kts` -- if present, confirms Java/Kotlin project; match dependency names against known JVM frameworks: `spring-boot`, `spring-web`, `spring-data`, `quarkus`, `micronaut`, `hibernate`, `jakarta`, `junit`, `ktor`
|
||||
|
||||
**Step 6 -- Complexity Estimation**
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ For every node, count how many other nodes it has edges pointing TO (fan-out). H
|
||||
**C. Entry Point Candidates**
|
||||
|
||||
Identify likely entry points using these signals (score each file node, sum the scores):
|
||||
- Filename matches `index.ts`, `index.js`, `main.ts`, `main.js`, `app.ts`, `app.js`, `server.ts`, `server.js`, `mod.rs`, `main.go`, `main.py`, `main.rs`, `manage.py`, `app.py`, `wsgi.py`, `asgi.py`, `run.py`, `__main__.py` -> +3 points
|
||||
- Filename matches `index.ts`, `index.js`, `main.ts`, `main.js`, `app.ts`, `app.js`, `server.ts`, `server.js`, `mod.rs`, `main.go`, `main.py`, `main.rs`, `manage.py`, `app.py`, `wsgi.py`, `asgi.py`, `run.py`, `__main__.py`, `Application.java`, `Main.java`, `Program.cs`, `config.ru`, `index.php`, `App.swift`, `Application.kt`, `main.cpp`, `main.c` -> +3 points
|
||||
- Node tags contain `entry-point` or `barrel` -> +2 points
|
||||
- File is at the project root or one level deep (e.g., `src/index.ts`) -> +1 point
|
||||
- High fan-out (top 10%) -> +1 point
|
||||
|
||||
Reference in New Issue
Block a user