fix: add dbml autocomplete (#1017)

This commit is contained in:
Guy Ben-Aharon
2025-12-17 17:13:44 +02:00
committed by GitHub
parent db1cf45a8a
commit fad5adc048
5 changed files with 147 additions and 4 deletions

17
package-lock.json generated
View File

@@ -9,7 +9,8 @@
"version": "1.19.0",
"dependencies": {
"@ai-sdk/openai": "^2.0.72",
"@dbml/core": "^3.13.9",
"@dbml/core": "^3.14.1",
"@dbml/parse": "^5.3.0",
"@dnd-kit/sortable": "^8.0.0",
"@monaco-editor/react": "^4.6.0",
"@radix-ui/react-accordion": "^1.2.0",
@@ -514,7 +515,7 @@
"node": ">=16"
}
},
"node_modules/@dbml/parse": {
"node_modules/@dbml/core/node_modules/@dbml/parse": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/@dbml/parse/-/parse-3.14.1.tgz",
"integrity": "sha512-I906RBlLF04IWQlMUw10EIKimafZ4STb86BC8hGnezb+wJqtAtVLAX8hfbzMDnGpjthm4jg0oddxTLFTZrk80g==",
@@ -526,6 +527,18 @@
"node": ">=18"
}
},
"node_modules/@dbml/parse": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/@dbml/parse/-/parse-5.3.0.tgz",
"integrity": "sha512-A9/kAdb/fdZvHC45L9vDO4k8mFXpLi9ZaFxrEjbZ5sxR/Y/cWRNBiWeiiwakvCbZoQCPbT9sWqfIbdqGy2sFzQ==",
"license": "Apache-2.0",
"dependencies": {
"lodash-es": "^4.17.21"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@dnd-kit/accessibility": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz",

View File

@@ -17,7 +17,8 @@
},
"dependencies": {
"@ai-sdk/openai": "^2.0.72",
"@dbml/core": "^3.13.9",
"@dbml/core": "^3.14.1",
"@dbml/parse": "^5.3.0",
"@dnd-kit/sortable": "^8.0.0",
"@monaco-editor/react": "^4.6.0",
"@radix-ui/react-accordion": "^1.2.0",

View File

@@ -0,0 +1,64 @@
import type { Monaco } from '@monaco-editor/react';
import type { IDisposable } from 'monaco-editor';
import { Compiler, services } from '@dbml/parse';
/**
* Creates and manages a DBML completion provider using @dbml/parse.
*
* The provider maintains a Compiler instance that needs to be kept in sync
* with the editor content to provide context-aware completions.
*/
export interface DBMLCompletionManager {
/** Disposable to clean up the completion provider registration */
dispose: () => void;
/** Update the compiler with new DBML content */
updateSource: (content: string) => void;
}
// Trigger characters for DBML completions
const TRIGGER_CHARACTERS = [' ', '[', ':', '.', '>', '<', '-'];
/**
* Registers a DBML completion provider with Monaco editor.
*
* Uses @dbml/parse's built-in DBMLCompletionItemProvider which provides:
* - Context-aware keyword suggestions (Table, Ref, Enum, etc.)
* - Symbol suggestions based on parsed DBML (table names, column names)
* - Field setting suggestions (pk, not null, unique, etc.)
* - Ref operator suggestions (>, <, -, <>)
*
* @param monaco - Monaco editor instance
* @param initialContent - Initial DBML content to parse
* @returns Manager object with dispose and updateSource methods
*/
export function registerDBMLCompletionProvider(
monaco: Monaco,
initialContent: string = ''
): DBMLCompletionManager {
const compiler = new Compiler();
// Initialize with content if provided
if (initialContent) {
compiler.setSource(initialContent);
}
// Create the completion provider from @dbml/parse
const completionProvider = new services.DBMLCompletionItemProvider(
compiler,
TRIGGER_CHARACTERS
);
// Register with Monaco
const disposable: IDisposable =
monaco.languages.registerCompletionItemProvider(
'dbml',
completionProvider
);
return {
dispose: () => disposable.dispose(),
updateSource: (content: string) => {
compiler.setSource(content);
},
};
}

View File

@@ -31,7 +31,12 @@ import {
clearErrorHighlight,
highlightErrorLine,
} from '@/components/code-snippet/dbml/utils';
import {
registerDBMLCompletionProvider,
type DBMLCompletionManager,
} from '@/components/code-snippet/dbml/dbml-completion-provider';
import type * as monaco from 'monaco-editor';
import type { Monaco } from '@monaco-editor/react';
import { useTranslation } from 'react-i18next';
import { useFullScreenLoader } from '@/hooks/use-full-screen-spinner';
@@ -58,9 +63,13 @@ export const TableDBML: React.FC<TableDBMLProps> = () => {
const editorRef = useRef<monaco.editor.IStandaloneCodeEditor>();
const decorationsCollection =
useRef<monaco.editor.IEditorDecorationsCollection>();
const completionManagerRef = useRef<DBMLCompletionManager>();
const handleEditorDidMount = useCallback(
(editor: monaco.editor.IStandaloneCodeEditor) => {
(
editor: monaco.editor.IStandaloneCodeEditor,
monacoInstance: Monaco
) => {
editorRef.current = editor;
decorationsCollection.current =
editor.createDecorationsCollection();
@@ -86,6 +95,13 @@ export const TableDBML: React.FC<TableDBMLProps> = () => {
});
readOnlyDisposableRef.current = readOnlyDisposable;
// Register DBML completion provider
completionManagerRef.current?.dispose();
completionManagerRef.current = registerDBMLCompletionProvider(
monacoInstance,
editor.getValue()
);
},
[]
);
@@ -304,6 +320,11 @@ export const TableDBML: React.FC<TableDBMLProps> = () => {
dbmlToDisplay,
]);
// Update completion provider when editor content changes
useEffect(() => {
completionManagerRef.current?.updateSource(editedDbml);
}, [editedDbml]);
useEffect(() => {
isMountedRef.current = true;
@@ -318,6 +339,11 @@ export const TableDBML: React.FC<TableDBMLProps> = () => {
readOnlyDisposableRef.current.dispose();
readOnlyDisposableRef.current = undefined;
}
if (completionManagerRef.current) {
completionManagerRef.current.dispose();
completionManagerRef.current = undefined;
}
};
}, []);

39
src/types/dbml-parse.d.ts vendored Normal file
View File

@@ -0,0 +1,39 @@
/**
* Type declarations for @dbml/parse
*
* The @dbml/parse package has types but they use path aliases (@/) that don't
* resolve properly when consumed as a dependency. This module provides the
* minimal types needed for the completion provider integration.
*/
declare module '@dbml/parse' {
import type { languages, editor } from 'monaco-editor';
/**
* DBML Compiler - parses and analyzes DBML content
*/
export class Compiler {
constructor();
setSource(source: string): void;
}
/**
* Completion item provider for Monaco editor
*/
export class DBMLCompletionItemProvider
implements languages.CompletionItemProvider
{
triggerCharacters?: string[];
constructor(compiler: Compiler, triggerCharacters?: string[]);
provideCompletionItems(
model: editor.ITextModel,
position: { lineNumber: number; column: number }
): languages.CompletionList;
}
/**
* Services namespace containing providers
*/
export namespace services {
export { DBMLCompletionItemProvider };
}
}