mirror of
https://github.com/samiyev/puaros.git
synced 2025-12-27 23:06:54 +05:00
feat(ipuaro): add interface fields and type alias definitions to context
- Add interface field display in initial context: interface User { id: string, name: string }
- Add type alias definition display: type UserId = string
- Support readonly fields, extends, union/intersection types
- Add definition field to TypeAliasInfo in FileAST
- Update ASTParser to extract type alias definitions
- Add formatInterfaceSignature() and formatTypeAliasSignature() helpers
- Truncate long type definitions at 80 characters
- Translate ROADMAP.md from Russian to English
- Add 18 new tests for interface fields and type aliases
This commit is contained in:
@@ -224,6 +224,62 @@ describe("ASTParser", () => {
|
||||
const ast = parser.parse(code, "ts")
|
||||
expect(ast.typeAliases[0].isExported).toBe(true)
|
||||
})
|
||||
|
||||
it("should extract type alias definition (simple)", () => {
|
||||
const code = `type UserId = string`
|
||||
const ast = parser.parse(code, "ts")
|
||||
expect(ast.typeAliases).toHaveLength(1)
|
||||
expect(ast.typeAliases[0].definition).toBe("string")
|
||||
})
|
||||
|
||||
it("should extract type alias definition (union)", () => {
|
||||
const code = `type Status = "pending" | "active" | "done"`
|
||||
const ast = parser.parse(code, "ts")
|
||||
expect(ast.typeAliases).toHaveLength(1)
|
||||
expect(ast.typeAliases[0].definition).toBe('"pending" | "active" | "done"')
|
||||
})
|
||||
|
||||
it("should extract type alias definition (intersection)", () => {
|
||||
const code = `type AdminUser = User & Admin`
|
||||
const ast = parser.parse(code, "ts")
|
||||
expect(ast.typeAliases).toHaveLength(1)
|
||||
expect(ast.typeAliases[0].definition).toBe("User & Admin")
|
||||
})
|
||||
|
||||
it("should extract type alias definition (object type)", () => {
|
||||
const code = `type Point = { x: number; y: number }`
|
||||
const ast = parser.parse(code, "ts")
|
||||
expect(ast.typeAliases).toHaveLength(1)
|
||||
expect(ast.typeAliases[0].definition).toBe("{ x: number; y: number }")
|
||||
})
|
||||
|
||||
it("should extract type alias definition (function type)", () => {
|
||||
const code = `type Handler = (event: Event) => void`
|
||||
const ast = parser.parse(code, "ts")
|
||||
expect(ast.typeAliases).toHaveLength(1)
|
||||
expect(ast.typeAliases[0].definition).toBe("(event: Event) => void")
|
||||
})
|
||||
|
||||
it("should extract type alias definition (generic)", () => {
|
||||
const code = `type Result<T> = { success: boolean; data: T }`
|
||||
const ast = parser.parse(code, "ts")
|
||||
expect(ast.typeAliases).toHaveLength(1)
|
||||
expect(ast.typeAliases[0].definition).toBe("{ success: boolean; data: T }")
|
||||
})
|
||||
|
||||
it("should extract type alias definition (array)", () => {
|
||||
const code = `type UserIds = string[]`
|
||||
const ast = parser.parse(code, "ts")
|
||||
expect(ast.typeAliases).toHaveLength(1)
|
||||
expect(ast.typeAliases[0].definition).toBe("string[]")
|
||||
})
|
||||
|
||||
it("should extract type alias definition (tuple)", () => {
|
||||
const code = `type Pair = [string, number]`
|
||||
const ast = parser.parse(code, "ts")
|
||||
expect(ast.typeAliases).toHaveLength(1)
|
||||
expect(ast.typeAliases[0].definition).toBe("[string, number]")
|
||||
})
|
||||
})
|
||||
|
||||
describe("exports", () => {
|
||||
|
||||
@@ -1086,4 +1086,412 @@ describe("prompts", () => {
|
||||
expect(context).toContain("- interface AdminUser extends User, Admin")
|
||||
})
|
||||
})
|
||||
|
||||
describe("interface fields (0.24.2)", () => {
|
||||
it("should format interface with fields", () => {
|
||||
const structure: ProjectStructure = {
|
||||
name: "test",
|
||||
rootPath: "/test",
|
||||
files: ["user.ts"],
|
||||
directories: [],
|
||||
}
|
||||
const asts = new Map<string, FileAST>([
|
||||
[
|
||||
"user.ts",
|
||||
{
|
||||
imports: [],
|
||||
exports: [],
|
||||
functions: [],
|
||||
classes: [],
|
||||
interfaces: [
|
||||
{
|
||||
name: "User",
|
||||
lineStart: 1,
|
||||
lineEnd: 5,
|
||||
properties: [
|
||||
{
|
||||
name: "id",
|
||||
line: 2,
|
||||
type: "string",
|
||||
visibility: "public",
|
||||
isStatic: false,
|
||||
isReadonly: false,
|
||||
},
|
||||
{
|
||||
name: "name",
|
||||
line: 3,
|
||||
type: "string",
|
||||
visibility: "public",
|
||||
isStatic: false,
|
||||
isReadonly: false,
|
||||
},
|
||||
{
|
||||
name: "email",
|
||||
line: 4,
|
||||
type: "string",
|
||||
visibility: "public",
|
||||
isStatic: false,
|
||||
isReadonly: false,
|
||||
},
|
||||
],
|
||||
extends: [],
|
||||
isExported: true,
|
||||
},
|
||||
],
|
||||
typeAliases: [],
|
||||
parseError: false,
|
||||
},
|
||||
],
|
||||
])
|
||||
|
||||
const context = buildInitialContext(structure, asts)
|
||||
|
||||
expect(context).toContain("interface User { id: string, name: string, email: string }")
|
||||
})
|
||||
|
||||
it("should format interface with extends and fields", () => {
|
||||
const structure: ProjectStructure = {
|
||||
name: "test",
|
||||
rootPath: "/test",
|
||||
files: ["types.ts"],
|
||||
directories: [],
|
||||
}
|
||||
const asts = new Map<string, FileAST>([
|
||||
[
|
||||
"types.ts",
|
||||
{
|
||||
imports: [],
|
||||
exports: [],
|
||||
functions: [],
|
||||
classes: [],
|
||||
interfaces: [
|
||||
{
|
||||
name: "AdminUser",
|
||||
lineStart: 1,
|
||||
lineEnd: 5,
|
||||
properties: [
|
||||
{
|
||||
name: "role",
|
||||
line: 2,
|
||||
type: "string",
|
||||
visibility: "public",
|
||||
isStatic: false,
|
||||
isReadonly: false,
|
||||
},
|
||||
],
|
||||
extends: ["User"],
|
||||
isExported: true,
|
||||
},
|
||||
],
|
||||
typeAliases: [],
|
||||
parseError: false,
|
||||
},
|
||||
],
|
||||
])
|
||||
|
||||
const context = buildInitialContext(structure, asts)
|
||||
|
||||
expect(context).toContain(
|
||||
"interface AdminUser extends User { role: string }",
|
||||
)
|
||||
})
|
||||
|
||||
it("should format interface with readonly fields", () => {
|
||||
const structure: ProjectStructure = {
|
||||
name: "test",
|
||||
rootPath: "/test",
|
||||
files: ["types.ts"],
|
||||
directories: [],
|
||||
}
|
||||
const asts = new Map<string, FileAST>([
|
||||
[
|
||||
"types.ts",
|
||||
{
|
||||
imports: [],
|
||||
exports: [],
|
||||
functions: [],
|
||||
classes: [],
|
||||
interfaces: [
|
||||
{
|
||||
name: "Config",
|
||||
lineStart: 1,
|
||||
lineEnd: 3,
|
||||
properties: [
|
||||
{
|
||||
name: "version",
|
||||
line: 2,
|
||||
type: "string",
|
||||
visibility: "public",
|
||||
isStatic: false,
|
||||
isReadonly: true,
|
||||
},
|
||||
],
|
||||
extends: [],
|
||||
isExported: true,
|
||||
},
|
||||
],
|
||||
typeAliases: [],
|
||||
parseError: false,
|
||||
},
|
||||
],
|
||||
])
|
||||
|
||||
const context = buildInitialContext(structure, asts)
|
||||
|
||||
expect(context).toContain("interface Config { readonly version: string }")
|
||||
})
|
||||
|
||||
it("should format interface with no type annotation", () => {
|
||||
const structure: ProjectStructure = {
|
||||
name: "test",
|
||||
rootPath: "/test",
|
||||
files: ["types.ts"],
|
||||
directories: [],
|
||||
}
|
||||
const asts = new Map<string, FileAST>([
|
||||
[
|
||||
"types.ts",
|
||||
{
|
||||
imports: [],
|
||||
exports: [],
|
||||
functions: [],
|
||||
classes: [],
|
||||
interfaces: [
|
||||
{
|
||||
name: "Loose",
|
||||
lineStart: 1,
|
||||
lineEnd: 3,
|
||||
properties: [
|
||||
{
|
||||
name: "data",
|
||||
line: 2,
|
||||
visibility: "public",
|
||||
isStatic: false,
|
||||
isReadonly: false,
|
||||
},
|
||||
],
|
||||
extends: [],
|
||||
isExported: true,
|
||||
},
|
||||
],
|
||||
typeAliases: [],
|
||||
parseError: false,
|
||||
},
|
||||
],
|
||||
])
|
||||
|
||||
const context = buildInitialContext(structure, asts)
|
||||
|
||||
expect(context).toContain("interface Loose { data }")
|
||||
})
|
||||
})
|
||||
|
||||
describe("type alias definitions (0.24.2)", () => {
|
||||
it("should format type alias with definition", () => {
|
||||
const structure: ProjectStructure = {
|
||||
name: "test",
|
||||
rootPath: "/test",
|
||||
files: ["types.ts"],
|
||||
directories: [],
|
||||
}
|
||||
const asts = new Map<string, FileAST>([
|
||||
[
|
||||
"types.ts",
|
||||
{
|
||||
imports: [],
|
||||
exports: [],
|
||||
functions: [],
|
||||
classes: [],
|
||||
interfaces: [],
|
||||
typeAliases: [
|
||||
{
|
||||
name: "UserId",
|
||||
line: 1,
|
||||
isExported: true,
|
||||
definition: "string",
|
||||
},
|
||||
],
|
||||
parseError: false,
|
||||
},
|
||||
],
|
||||
])
|
||||
|
||||
const context = buildInitialContext(structure, asts)
|
||||
|
||||
expect(context).toContain("- type UserId = string")
|
||||
})
|
||||
|
||||
it("should format union type alias", () => {
|
||||
const structure: ProjectStructure = {
|
||||
name: "test",
|
||||
rootPath: "/test",
|
||||
files: ["types.ts"],
|
||||
directories: [],
|
||||
}
|
||||
const asts = new Map<string, FileAST>([
|
||||
[
|
||||
"types.ts",
|
||||
{
|
||||
imports: [],
|
||||
exports: [],
|
||||
functions: [],
|
||||
classes: [],
|
||||
interfaces: [],
|
||||
typeAliases: [
|
||||
{
|
||||
name: "Status",
|
||||
line: 1,
|
||||
isExported: true,
|
||||
definition: '"pending" | "active" | "done"',
|
||||
},
|
||||
],
|
||||
parseError: false,
|
||||
},
|
||||
],
|
||||
])
|
||||
|
||||
const context = buildInitialContext(structure, asts)
|
||||
|
||||
expect(context).toContain('- type Status = "pending" | "active" | "done"')
|
||||
})
|
||||
|
||||
it("should format intersection type alias", () => {
|
||||
const structure: ProjectStructure = {
|
||||
name: "test",
|
||||
rootPath: "/test",
|
||||
files: ["types.ts"],
|
||||
directories: [],
|
||||
}
|
||||
const asts = new Map<string, FileAST>([
|
||||
[
|
||||
"types.ts",
|
||||
{
|
||||
imports: [],
|
||||
exports: [],
|
||||
functions: [],
|
||||
classes: [],
|
||||
interfaces: [],
|
||||
typeAliases: [
|
||||
{
|
||||
name: "AdminUser",
|
||||
line: 1,
|
||||
isExported: true,
|
||||
definition: "User & Admin",
|
||||
},
|
||||
],
|
||||
parseError: false,
|
||||
},
|
||||
],
|
||||
])
|
||||
|
||||
const context = buildInitialContext(structure, asts)
|
||||
|
||||
expect(context).toContain("- type AdminUser = User & Admin")
|
||||
})
|
||||
|
||||
it("should truncate long type definitions", () => {
|
||||
const structure: ProjectStructure = {
|
||||
name: "test",
|
||||
rootPath: "/test",
|
||||
files: ["types.ts"],
|
||||
directories: [],
|
||||
}
|
||||
const longDefinition =
|
||||
"{ id: string, name: string, email: string, phone: string, address: string, city: string, country: string, zip: string }"
|
||||
const asts = new Map<string, FileAST>([
|
||||
[
|
||||
"types.ts",
|
||||
{
|
||||
imports: [],
|
||||
exports: [],
|
||||
functions: [],
|
||||
classes: [],
|
||||
interfaces: [],
|
||||
typeAliases: [
|
||||
{
|
||||
name: "BigType",
|
||||
line: 1,
|
||||
isExported: true,
|
||||
definition: longDefinition,
|
||||
},
|
||||
],
|
||||
parseError: false,
|
||||
},
|
||||
],
|
||||
])
|
||||
|
||||
const context = buildInitialContext(structure, asts)
|
||||
|
||||
expect(context).toContain("- type BigType = { id: string")
|
||||
expect(context).toContain("...")
|
||||
})
|
||||
|
||||
it("should format type alias without definition (fallback)", () => {
|
||||
const structure: ProjectStructure = {
|
||||
name: "test",
|
||||
rootPath: "/test",
|
||||
files: ["types.ts"],
|
||||
directories: [],
|
||||
}
|
||||
const asts = new Map<string, FileAST>([
|
||||
[
|
||||
"types.ts",
|
||||
{
|
||||
imports: [],
|
||||
exports: [],
|
||||
functions: [],
|
||||
classes: [],
|
||||
interfaces: [],
|
||||
typeAliases: [
|
||||
{
|
||||
name: "Unknown",
|
||||
line: 1,
|
||||
isExported: true,
|
||||
},
|
||||
],
|
||||
parseError: false,
|
||||
},
|
||||
],
|
||||
])
|
||||
|
||||
const context = buildInitialContext(structure, asts)
|
||||
|
||||
expect(context).toContain("- type Unknown")
|
||||
expect(context).not.toContain("- type Unknown =")
|
||||
})
|
||||
|
||||
it("should format function type alias", () => {
|
||||
const structure: ProjectStructure = {
|
||||
name: "test",
|
||||
rootPath: "/test",
|
||||
files: ["types.ts"],
|
||||
directories: [],
|
||||
}
|
||||
const asts = new Map<string, FileAST>([
|
||||
[
|
||||
"types.ts",
|
||||
{
|
||||
imports: [],
|
||||
exports: [],
|
||||
functions: [],
|
||||
classes: [],
|
||||
interfaces: [],
|
||||
typeAliases: [
|
||||
{
|
||||
name: "Handler",
|
||||
line: 1,
|
||||
isExported: true,
|
||||
definition: "(event: Event) => void",
|
||||
},
|
||||
],
|
||||
parseError: false,
|
||||
},
|
||||
],
|
||||
])
|
||||
|
||||
const context = buildInitialContext(structure, asts)
|
||||
|
||||
expect(context).toContain("- type Handler = (event: Event) => void")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user