From 8dfc99572fcb3d8610f8ce19c7e8cb42df7163d6 Mon Sep 17 00:00:00 2001 From: Olaf Monien Date: Wed, 11 Feb 2026 01:06:16 +0100 Subject: [PATCH] =?UTF-8?q?Delphi-Konzept:=20DFM/FMX=20Support=20hinzugef?= =?UTF-8?q?=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Neues Dokument 07-DFM-FMX-Support.md: Format-Referenz, Extraktions-Strategie, DfmExtractor-Konzept - Neues Fixture MainForm.dfm: Verschachtelte Komponenten, Event-Handler (FormCreate, btnLoginClick, etc.) - Integration Guide erweitert: DfmExtractor-Implementierung (analog LiquidExtractor), Coding-Style-Hinweise - NodeKind-Mapping erweitert: DFM-Komponenten als component, Event-Handler als references, Verschachtelung als contains - Checklist: DFM/FMX von 'Zukunft' auf konkreten Plan (Phase 1b) hochgestuft - README aktualisiert: DFM/FMX-Support in Ziel, Inhalt und Grammar-Abschnitt aufgenommen --- Delphi/Docs/04-Checklist.md | 18 ++- Delphi/Docs/05-NodeKind-Mapping.md | 21 ++- Delphi/Docs/06-Integration-Guide.md | 217 +++++++++++++++++++++++++++- Delphi/Docs/07-DFM-FMX-Support.md | 149 +++++++++++++++++++ Delphi/README.md | 15 +- Delphi/fixtures/MainForm.dfm | 92 ++++++++++++ 6 files changed, 499 insertions(+), 13 deletions(-) create mode 100644 Delphi/Docs/07-DFM-FMX-Support.md create mode 100644 Delphi/fixtures/MainForm.dfm diff --git a/Delphi/Docs/04-Checklist.md b/Delphi/Docs/04-Checklist.md index 496fa78..00a59b1 100644 --- a/Delphi/Docs/04-Checklist.md +++ b/Delphi/Docs/04-Checklist.md @@ -3,9 +3,9 @@ ## A) Plumbing (Infrastruktur) - [ ] `npm install tree-sitter-pascal` als Dependency - [ ] `src/types.ts`: `'pascal'` zum `Language` Union-Type hinzufügen -- [ ] `src/types.ts`: `DEFAULT_CONFIG.include` um `'**/*.pas'`, `'**/*.dpr'`, `'**/*.dpk'`, `'**/*.lpr'` erweitern +- [ ] `src/types.ts`: `DEFAULT_CONFIG.include` um `'**/*.pas'`, `'**/*.dpr'`, `'**/*.dpk'`, `'**/*.lpr'`, `'**/*.dfm'`, `'**/*.fmx'` erweitern - [ ] `src/extraction/grammars.ts`: Grammar-Loader `pascal: () => require('tree-sitter-pascal')` -- [ ] `src/extraction/grammars.ts`: Extension-Mapping `.pas`, `.dpr`, `.dpk`, `.lpr` → `'pascal'` +- [ ] `src/extraction/grammars.ts`: Extension-Mapping `.pas`, `.dpr`, `.dpk`, `.lpr`, `.dfm`, `.fmx` → `'pascal'` - [ ] `src/extraction/grammars.ts`: Display-Name `pascal: 'Pascal / Delphi'` - [ ] `src/extraction/tree-sitter.ts`: `LanguageExtractor` für `pascal` in `EXTRACTORS` Map @@ -53,9 +53,19 @@ - [ ] Language in Supported-Languages-Dokumentation aufnehmen - [ ] CLI-Hilfe / Config-Validierung aktualisieren -## H) Bekannte Einschränkungen (für spätere Phasen) +## H) DFM/FMX Form-Dateien (Phase 1b) +- [ ] `DfmExtractor`-Klasse in `src/extraction/tree-sitter.ts` implementieren (analog `LiquidExtractor`) +- [ ] Routing in `extractFromSource()`: `.dfm`/`.fmx` → `DfmExtractor` +- [ ] Komponenten als NodeKind `component` extrahieren (`object : `) +- [ ] Verschachtelung als EdgeKind `contains` abbilden +- [ ] Event-Handler (`OnClick = MethodName`) als `UnresolvedReference` speichern → EdgeKind `references` +- [ ] Mehrzeilige Properties korrekt überspringen +- [ ] `inherited`-Blöcke als `component` behandeln +- [ ] DFM-Fixture (`MainForm.dfm`) in Test-Suite aufnehmen +- [ ] Resolution: Event-Handler-Namen zu Methoden in zugehöriger `.pas`-Datei auflösen + +## I) Bekannte Einschränkungen (für spätere Phasen) - [ ] **`with`-Statements** (Phase 2): Verschleiern den Qualifier bei Aufrufen. Im MVP werden Calls innerhalb von `with`-Blöcken ohne Qualifier extrahiert. -- [ ] **`.dfm`/`.fmx` Form-Dateien** (Zukunft): Enthalten Komponenten-Deklarationen und Event-Verknüpfungen. Aktuell nicht unterstützt. - [ ] **`.inc` Include-Dateien** (Optional): Enthalten Code-Fragmente, die per `{$I filename}` eingebunden werden. Parser liefert möglicherweise keinen vollständigen AST. - [ ] **Class Helpers / Record Helpers** (Phase 2): `declHelper`-Knoten erweitern existierende Typen. Erfordert spezielle Resolution-Logik. - [ ] **Generics** (Phase 2): `typerefTpl` und `genericTpl` für generische Typen. diff --git a/Delphi/Docs/05-NodeKind-Mapping.md b/Delphi/Docs/05-NodeKind-Mapping.md index b84cfed..5c8660d 100644 --- a/Delphi/Docs/05-NodeKind-Mapping.md +++ b/Delphi/Docs/05-NodeKind-Mapping.md @@ -43,13 +43,32 @@ Dieses Dokument zeigt die explizite Zuordnung von Delphi/Pascal-Konzepten zu den | Unit enthält Klasse | AST Parent-Child | `contains` | | Klasse enthält Methode | AST Parent-Child | `contains` | +## DFM/FMX Node-Mapping + +DFM/FMX-Dateien werden durch einen eigenen `DfmExtractor` (Regex-basiert, analog `LiquidExtractor`) verarbeitet. + +| DFM-Konzept | Erkennung | CodeGraph `NodeKind` | Anmerkungen | +|---|---|---|---| +| Formular | `object Form1: TForm1` (Top-Level) | `component` | Root-Komponente der DFM-Datei | +| UI-Komponente | `object Button1: TButton` (verschachtelt) | `component` | Jede Komponente wird ein Node | +| Geerbte Komponente | `inherited Form1: TForm1` | `component` | Formular-Vererbung | + +## DFM/FMX Edge-Mapping + +| DFM-Beziehung | Erkennung | CodeGraph `EdgeKind` | Beschreibung | +|---|---|---|---| +| Verschachtelung | `object` innerhalb `object` | `contains` | Panel1 enthält Button1 | +| Event-Handler | `OnClick = Button1Click` | `references` | Komponente → Methode in `.pas` | +| Datei enthält Formular | Top-Level `object` | `contains` | DFM-Datei → Root-Komponente | + +> **Hinweis:** Event-Handler-Verknüpfungen werden als `UnresolvedReference` gespeichert und in der Resolution-Phase zur entsprechenden Methode in der zugehörigen `.pas`-Datei aufgelöst. + ## Nicht abgebildete Konzepte (Phase 2+) | Konzept | Grund | |---|---| | `with`-Statement | Kein eigener EdgeKind nötig; erschwert nur die Call-Qualifizierung | | Class Helper | Kein eigener NodeKind; als `class` mit speziellem Bezug zum erweiterten Typ | -| `.dfm`/`.fmx` Komponenten | Kein Code im Pascal-Sinne; erfordert eigenen Parser | | `exports`-Klauseln | `declExports` → könnte als `export` NodeKind abgebildet werden | | Generics | `typerefTpl` → beeinflusst Typ-Referenzen, nicht den NodeKind | diff --git a/Delphi/Docs/06-Integration-Guide.md b/Delphi/Docs/06-Integration-Guide.md index 44f8d2f..ff9f109 100644 --- a/Delphi/Docs/06-Integration-Guide.md +++ b/Delphi/Docs/06-Integration-Guide.md @@ -134,9 +134,224 @@ pascal: { }, ``` -## Hinweise +## Hinweise zur Pascal-Integration - `declProc` wird sowohl für `functionTypes` als auch `methodTypes` verwendet. CodeGraph unterscheidet anhand des AST-Kontexts (Parent ist `declClass` → method, sonst → function). - Die `getVisibility`-Funktion traversiert aufwärts zum `declSection`-Knoten. - Records werden als `class` behandelt, da `declClass` mit `kRecord` Kind-Knoten beides abdeckt. +--- + +## 5) DFM/FMX-Support: Custom Extractor + +DFM/FMX-Dateien verwenden ein einfaches zeilenbasiertes Textformat (kein tree-sitter Parser vorhanden). Die Integration erfolgt analog zu `LiquidExtractor` und `SvelteExtractor` als **Custom Extractor**. + +### Extension-Mapping ergänzen (`src/extraction/grammars.ts`) + +```typescript +export const EXTENSION_MAP: Record = { + // ...bestehende Mappings... + '.pas': 'pascal', + '.dpr': 'pascal', + '.dpk': 'pascal', + '.lpr': 'pascal', + '.dfm': 'pascal', // ← NEU: DFM-Formulare + '.fmx': 'pascal', // ← NEU: FMX-Formulare +}; +``` + +> **Hinweis:** DFM/FMX werden als Sprache `pascal` registriert. Die Unterscheidung zwischen tree-sitter-Parsing (`.pas`) und Custom Extractor (`.dfm`/`.fmx`) erfolgt in `extractFromSource()` anhand der Dateiendung. + +### DEFAULT_CONFIG.include ergänzen (`src/types.ts`) + +```typescript +include: [ + // ...bestehende Patterns... + '**/*.pas', + '**/*.dpr', + '**/*.dpk', + '**/*.lpr', + '**/*.dfm', // ← NEU + '**/*.fmx', // ← NEU +], +``` + +### Routing in `extractFromSource()` (`src/extraction/tree-sitter.ts`) + +```typescript +export function extractFromSource( + filePath: string, + source: string, + language?: Language +): ExtractionResult { + const detectedLanguage = language || detectLanguage(filePath); + + // Use custom extractor for Svelte + if (detectedLanguage === 'svelte') { + const extractor = new SvelteExtractor(filePath, source); + return extractor.extract(); + } + + // Use custom extractor for Liquid + if (detectedLanguage === 'liquid') { + const extractor = new LiquidExtractor(filePath, source); + return extractor.extract(); + } + + // Use custom extractor for DFM/FMX form files ← NEU + if (detectedLanguage === 'pascal' && + (filePath.endsWith('.dfm') || filePath.endsWith('.fmx'))) { + const extractor = new DfmExtractor(filePath, source); + return extractor.extract(); + } + + const extractor = new TreeSitterExtractor(filePath, source, detectedLanguage); + return extractor.extract(); +} +``` + +### DfmExtractor Klasse (Coding Style analog LiquidExtractor) + +```typescript +/** + * Custom extractor for Delphi DFM/FMX form files. + * + * DFM/FMX files describe the visual component hierarchy and event handler + * bindings. They use a simple text format (object/end blocks) that we parse + * with regex — no tree-sitter grammar exists for this format. + * + * Extracted information: + * - Components as NodeKind `component` + * - Nesting as EdgeKind `contains` + * - Event handlers (OnClick = MethodName) as UnresolvedReference → EdgeKind `references` + */ +export class DfmExtractor { + private filePath: string; + private source: string; + private nodes: Node[] = []; + private edges: Edge[] = []; + private unresolvedReferences: UnresolvedReference[] = []; + private errors: ExtractionError[] = []; + + constructor(filePath: string, source: string) { + this.filePath = filePath; + this.source = source; + } + + /** + * Extract components and event handler references from DFM/FMX source + */ + extract(): ExtractionResult { + const startTime = Date.now(); + + try { + const fileNode = this.createFileNode(); + this.parseComponents(fileNode.id); + } catch (error) { + captureException(error, { operation: 'dfm-extraction', filePath: this.filePath }); + this.errors.push({ + message: `DFM extraction error: ${error instanceof Error ? error.message : String(error)}`, + severity: 'error', + }); + } + + return { + nodes: this.nodes, + edges: this.edges, + unresolvedReferences: this.unresolvedReferences, + errors: this.errors, + durationMs: Date.now() - startTime, + }; + } + + /** Create a file node for the DFM form file */ + private createFileNode(): Node { /* ... analog LiquidExtractor ... */ } + + /** Parse object/end blocks and extract components + event handlers */ + private parseComponents(fileNodeId: string): void { + const lines = this.source.split('\n'); + const stack: string[] = [fileNodeId]; // Stack der Parent-Node-IDs + + const objectPattern = /^\s*(object|inherited|inline)\s+(\w+)\s*:\s*(\w+)/; + const eventPattern = /^\s*(On\w+)\s*=\s*(\w+)/; + const endPattern = /^\s*end\s*$/; + const multiLineStart = /=\s*\(\s*$/; + let inMultiLine = false; + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + const lineNum = i + 1; + + // Mehrzeilige Properties überspringen + if (inMultiLine) { + if (line.trimEnd().endsWith(')')) inMultiLine = false; + continue; + } + if (multiLineStart.test(line)) { + inMultiLine = true; + continue; + } + + // Component-Deklaration + const objMatch = line.match(objectPattern); + if (objMatch) { + const [, , name, typeName] = objMatch; + const nodeId = generateNodeId(this.filePath, 'component', name, lineNum); + this.nodes.push({ + id: nodeId, + kind: 'component', + name, + qualifiedName: `${this.filePath}#${name}`, + filePath: this.filePath, + language: 'pascal', + startLine: lineNum, + endLine: lineNum, // wird beim zugehörigen 'end' aktualisiert + startColumn: 0, + endColumn: line.length, + metadata: { componentType: typeName }, + updatedAt: Date.now(), + }); + this.edges.push({ + source: stack[stack.length - 1], + target: nodeId, + kind: 'contains', + }); + stack.push(nodeId); + continue; + } + + // Event-Handler + const eventMatch = line.match(eventPattern); + if (eventMatch) { + const [, , methodName] = eventMatch; + this.unresolvedReferences.push({ + sourceNodeId: stack[stack.length - 1], + targetName: methodName, + kind: 'references', + filePath: this.filePath, + line: lineNum, + }); + continue; + } + + // Block-Ende + if (endPattern.test(line)) { + if (stack.length > 1) stack.pop(); + } + } + } +} +``` + +### Coding-Style-Hinweise + +Der `DfmExtractor` folgt dem bestehenden Coding Style der Custom Extractors: + +- **JSDoc-Kommentare** (`/** */`) für jede öffentliche Methode und die Klasse selbst +- **Private Felder** für `nodes`, `edges`, `unresolvedReferences`, `errors` +- **`generateNodeId()`** für deterministische Node-IDs +- **`captureException()`** für Error-Tracking in catch-Blöcken +- **`ExtractionResult`** als Return-Type von `extract()` +- **`UnresolvedReference`** für Event-Handler (werden in der Resolution-Phase aufgelöst) +- **Kein tree-sitter** — rein Regex/zeilenbasiertes Parsing + diff --git a/Delphi/Docs/07-DFM-FMX-Support.md b/Delphi/Docs/07-DFM-FMX-Support.md new file mode 100644 index 0000000..93a330f --- /dev/null +++ b/Delphi/Docs/07-DFM-FMX-Support.md @@ -0,0 +1,149 @@ +# DFM/FMX Form-Dateien: Format-Referenz & Extraktions-Konzept + +Delphi-Projekte bestehen nicht nur aus `.pas`-Dateien, sondern auch aus **Form-Dateien** (`.dfm` für VCL, `.fmx` für FireMonkey). Diese enthalten die visuelle Komponentenhierarchie und — besonders wertvoll für CodeGraph — die **Event-Handler-Verknüpfungen** zwischen UI-Komponenten und Pascal-Methoden. + +## Warum DFM/FMX für CodeGraph relevant sind + +| Information | Wert für CodeGraph | +|---|---| +| Komponenten-Deklarationen (`object Button1: TButton`) | NodeKind `component` — zeigt welche UI-Elemente existieren | +| Event-Handler (`OnClick = Button1Click`) | EdgeKind `references` — verknüpft UI mit Code in `.pas` | +| Komponenten-Hierarchie (verschachtelte `object`-Blöcke) | EdgeKind `contains` — zeigt Parent-Child-Beziehungen | +| Komponenten-Typ (`TButton`, `TPanel`, `TEdit`) | Metadata — Typ-Information für Impact-Analyse | + +**Besonders wertvoll:** Wenn ein Entwickler eine Methode in der `.pas`-Datei umbenennt, zeigt CodeGraph sofort, dass ein DFM-Event-Handler darauf verweist → Impact-Analyse funktioniert über Dateigrenzen hinweg. + +## DFM-Textformat + +DFM-Dateien können in **Text** oder **Binär** gespeichert werden. Moderne Delphi-Projekte verwenden fast ausschließlich das Textformat (besser für Versionskontrolle). FMX-Dateien verwenden das gleiche Textformat. + +### Grundstruktur + +``` +object Form1: TForm1 + Left = 0 + Top = 0 + Caption = 'Hauptformular' + ClientHeight = 400 + ClientWidth = 600 + OnCreate = FormCreate + OnDestroy = FormDestroy + object Panel1: TPanel + Left = 0 + Top = 0 + Width = 600 + Height = 50 + Align = alTop + object Label1: TLabel + Left = 16 + Top = 16 + Caption = 'Willkommen' + end + object Button1: TButton + Left = 500 + Top = 12 + Caption = 'Login' + OnClick = Button1Click + end + end + object Memo1: TMemo + Left = 0 + Top = 50 + Width = 600 + Height = 350 + Align = alClient + end +end +``` + +### Syntax-Regeln + +1. **Top-Level:** `object : ` — das Formular selbst +2. **Verschachtelte Komponenten:** `object : ` innerhalb eines anderen `object`-Blocks +3. **Properties:** ` = ` — einfache Zuweisung +4. **Event-Handler:** `On = ` — Verknüpfung zu Pascal-Methode +5. **Ende:** `end` schließt jeden `object`-Block +6. **Vererbung:** `inherited : ` statt `object` bei geerbten Formularen +7. **Inline-Objekte:** `inline : ` für inline erstellte Objekte + +### Event-Handler erkennen + +Event-Handler sind Properties, deren **Key mit `On` beginnt** und deren **Value ein Bezeichner** (kein String, keine Zahl) ist: + +``` +OnClick = Button1Click ← Event-Handler → references Button1Click +OnChange = EditChanged ← Event-Handler → references EditChanged +Caption = 'Nicht ein Event' ← Normales Property (String-Wert) +Left = 100 ← Normales Property (Zahl-Wert) +Align = alTop ← Normales Property (Enum-Wert) +``` + +### Mehrzeilige Properties + +Einige Properties erstrecken sich über mehrere Zeilen: + +``` + SQL.Strings = ( + 'SELECT * FROM users' + 'WHERE active = 1' + 'ORDER BY name') + Items.Strings = ( + 'Option A' + 'Option B') +``` + +Diese sind für CodeGraph weniger relevant, müssen aber beim Parsen korrekt übersprungen werden. + +## Extraktions-Strategie: DfmExtractor + +Analog zum `LiquidExtractor` und `SvelteExtractor` wird ein **`DfmExtractor`** als Custom Extractor implementiert — **ohne tree-sitter**, rein Regex/Zeilen-basiert. + +### Zu extrahierende Nodes + +| DFM-Element | CodeGraph NodeKind | Beispiel | +|---|---|---| +| Top-Level `object` | `component` | `Form1: TForm1` | +| Verschachtelte `object` | `component` | `Button1: TButton` | +| `inherited` | `component` | Geerbte Komponente | + +### Zu extrahierende Edges + +| DFM-Beziehung | CodeGraph EdgeKind | Beschreibung | +|---|---|---| +| Verschachtelung | `contains` | Panel1 enthält Button1 | +| Event-Handler | `references` | Button1 → `Button1Click` (Methode in .pas) | +| Datei enthält Komponente | `contains` | DFM-Datei → Form1 | + +### Parsing-Algorithmus (Pseudocode) + +``` +für jede Zeile: + wenn "object : " oder "inherited : ": + → neuen component-Node erstellen + → contains-Edge vom Parent + → auf Stack pushen + wenn "end": + → Stack poppen + wenn " = " und Key beginnt mit "On" und Value ist Bezeichner: + → references-Edge: aktuelle Komponente → Value (Methodenname) + → als UnresolvedReference speichern (wird später zur .pas-Methode aufgelöst) + wenn mehrzeiliges Property (endet mit "("): + → Zeilen überspringen bis ")" +``` + +### Verknüpfung DFM ↔ PAS + +Die Zuordnung DFM → PAS erfolgt über den **Dateinamen**: +- `MainForm.dfm` gehört zu `MainForm.pas` (gleicher Basename) +- Event-Handler `Button1Click` → Methode `TForm1.Button1Click` in der zugehörigen `.pas`-Datei + +Diese Verknüpfung erfolgt in der **Resolution-Phase**, nicht beim Parsen. + +## Kein tree-sitter nötig + +Es gibt keinen tree-sitter Parser für DFM/FMX. Das Format ist aber so einfach strukturiert (zeilenbasiert, keine komplexe Grammatik), dass ein Regex-basierter Parser vollkommen ausreicht — genau wie bei Liquid-Templates. + +## Phase + +DFM/FMX-Support wird als **Phase 1b** eingeplant — parallel zum Pascal-Support, da die Verknüpfung DFM ↔ PAS den größten Mehrwert liefert, wenn beides gleichzeitig verfügbar ist. + diff --git a/Delphi/README.md b/Delphi/README.md index 1089b79..304616f 100644 --- a/Delphi/README.md +++ b/Delphi/README.md @@ -2,7 +2,7 @@ Dieses Verzeichnis enthält einen **umsetzbaren Bauplan** für Pascal/Delphi-Support in CodeGraph. Es basiert auf der tatsächlichen CodeGraph-Architektur und den verifizierten AST-Knotentypen von [`tree-sitter-pascal`](https://github.com/Isopod/tree-sitter-pascal). -**Ziel:** CodeGraph soll **Pascal/Delphi**-Dateien indexieren und daraus **Nodes** (Units, Klassen, Methoden, Properties, Enums, …) sowie **Edges** (uses/imports, calls, extends, implements, …) extrahieren. +**Ziel:** CodeGraph soll **Pascal/Delphi**-Dateien indexieren und daraus **Nodes** (Units, Klassen, Methoden, Properties, Enums, …) sowie **Edges** (uses/imports, calls, extends, implements, …) extrahieren. Zusätzlich werden **DFM/FMX-Formulardateien** unterstützt, um UI-Komponenten und Event-Handler-Verknüpfungen zu erfassen. ## Inhalt @@ -13,8 +13,9 @@ Dieses Verzeichnis enthält einen **umsetzbaren Bauplan** für Pascal/Delphi-Sup | `Docs/03-AST-Referenz.md` | Verifizierte AST-Knotentypen aus tree-sitter-pascal | | `Docs/04-Checklist.md` | Umsetzungs-Checkliste mit bekannten Einschränkungen | | `Docs/05-NodeKind-Mapping.md` | Explizite Zuordnung Delphi → CodeGraph NodeKind/EdgeKind | -| `Docs/06-Integration-Guide.md` | Konkrete Code-Diffs für `grammars.ts`, `types.ts`, `tree-sitter.ts` | -| `fixtures/` | Delphi-Beispieldateien zum Testen der Extraktion | +| `Docs/06-Integration-Guide.md` | Konkrete Code-Diffs für `grammars.ts`, `types.ts`, `tree-sitter.ts` + DfmExtractor | +| `Docs/07-DFM-FMX-Support.md` | DFM/FMX Form-Dateien: Format-Referenz & Extraktions-Konzept | +| `fixtures/` | Delphi-Beispieldateien zum Testen (`.pas`, `.dpr`, `.dfm`) | | `resolution/` | Resolver-Heuristiken (Unit-Mapping, Call-Resolution) | ## Architektur-Übersicht @@ -33,8 +34,8 @@ CodeGraph verwendet **keine** per-Sprache Plugin-Verzeichnisse. Die Integration 4. **Resolver erweitern** (mindestens `uses` → Unit-File, einfache Call-Auflösung) 5. **Fixtures in die Tests aufnehmen** und Assertions hinzufügen -## Grammar +## Grammar & Parsing -Verwendet wird: [`tree-sitter-pascal`](https://github.com/Isopod/tree-sitter-pascal) (npm: `tree-sitter-pascal`) -- Unterstützt: Delphi, FreePascal, Standard-Pascal -- Dateierweiterungen: `.pas`, `.dpr`, `.dpk`, `.lpr` +**Pascal-Dateien** (`.pas`, `.dpr`, `.dpk`, `.lpr`) werden mit [`tree-sitter-pascal`](https://github.com/Isopod/tree-sitter-pascal) geparst (AST-basierte Extraktion via `LanguageExtractor`). + +**DFM/FMX-Dateien** (`.dfm`, `.fmx`) werden mit einem **Custom Extractor** (`DfmExtractor`) verarbeitet — analog zu `LiquidExtractor` und `SvelteExtractor`. Das DFM-Textformat ist zeilenbasiert und wird per Regex geparst. Besonders wertvoll: Event-Handler wie `OnClick = Button1Click` erzeugen `references`-Edges zu den zugehörigen Methoden in der `.pas`-Datei. diff --git a/Delphi/fixtures/MainForm.dfm b/Delphi/fixtures/MainForm.dfm new file mode 100644 index 0000000..998536e --- /dev/null +++ b/Delphi/fixtures/MainForm.dfm @@ -0,0 +1,92 @@ +object frmMain: TfrmMain + Left = 0 + Top = 0 + Caption = 'CodeGraph DFM Fixture' + ClientHeight = 480 + ClientWidth = 640 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -12 + Font.Name = 'Segoe UI' + OnCreate = FormCreate + OnDestroy = FormDestroy + PixelsPerInch = 96 + TextHeight = 15 + object pnlTop: TPanel + Left = 0 + Top = 0 + Width = 640 + Height = 50 + Align = alTop + BevelOuter = bvNone + TabOrder = 0 + object lblTitle: TLabel + Left = 16 + Top = 16 + Width = 200 + Height = 15 + Caption = 'Authentication Service' + end + object btnLogin: TButton + Left = 540 + Top = 12 + Width = 80 + Height = 25 + Caption = 'Login' + TabOrder = 0 + OnClick = btnLoginClick + end + end + object pnlContent: TPanel + Left = 0 + Top = 50 + Width = 640 + Height = 390 + Align = alClient + BevelOuter = bvNone + TabOrder = 1 + object edtUsername: TEdit + Left = 16 + Top = 16 + Width = 300 + Height = 23 + TabOrder = 0 + TextHint = 'Username' + OnChange = edtUsernameChange + end + object edtPassword: TEdit + Left = 16 + Top = 48 + Width = 300 + Height = 23 + PasswordChar = '*' + TabOrder = 1 + TextHint = 'Password' + OnKeyPress = edtPasswordKeyPress + end + object mmoLog: TMemo + Left = 16 + Top = 88 + Width = 608 + Height = 280 + ReadOnly = True + ScrollBars = ssVertical + TabOrder = 2 + end + end + object pnlStatus: TStatusBar + Left = 0 + Top = 440 + Width = 640 + Height = 40 + Panels = < + item + Width = 200 + end + item + Width = 200 + end> + end +end +