diff --git a/README.md b/README.md index 331b832..d18867f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![build-status](https://github.com/alswl/dbml-editor/actions/workflows/ci.yaml/badge.svg) -Online editor for [DBML](https://dbml.dbdiagram.io/home/) files. +Free online editor [DBML](https://dbml.dbdiagram.io/home/) editor. ## Online Editor @@ -10,8 +10,10 @@ Online editor for [DBML](https://dbml.dbdiagram.io/home/) files. ## Features -- Syntax highlighting +- DBML syntax highlighting - Live preview +- Import from SQL +- Export to SQL ## Alternatives @@ -22,6 +24,8 @@ Online editor for [DBML](https://dbml.dbdiagram.io/home/) files. ## Roadmap -- Full support for DBML feature -- Export to SQL -- Import from SQL +- Better syntax highlighting +- Editor inline error hint +- hidden foreign key +- better style based on note +- ER positions save and restore diff --git a/src/components/viewer/viewer.tsx b/src/components/viewer/viewer.tsx index 19113d5..e4c4556 100644 --- a/src/components/viewer/viewer.tsx +++ b/src/components/viewer/viewer.tsx @@ -1,4 +1,4 @@ -import parseDatabaseToER from '@/parser/parser'; +import parseDatabaseToER from '@/services/er'; import { DagreLayout } from '@antv/layout'; import { Graph, Model } from '@antv/x6'; import { Snapline } from '@antv/x6-plugin-snapline'; diff --git a/src/global.ts b/src/global.ts index 24be6ad..925989b 100644 --- a/src/global.ts +++ b/src/global.ts @@ -1,5 +1,5 @@ -import registerSyntax from '@/editor/syntax'; import registerER from '@/nodes/er'; +import registerSyntax from '@/services/editor/syntax'; registerER(); registerSyntax(); diff --git a/src/pages/Home/index.tsx b/src/pages/Home/index.tsx index b384474..82029b1 100644 --- a/src/pages/Home/index.tsx +++ b/src/pages/Home/index.tsx @@ -1,4 +1,4 @@ -import { CompilerDiagnostic, exporter, importer, Parser } from '@dbml/core'; +import { exporter, importer, Parser } from '@dbml/core'; import { Col, FloatButton, message, Modal, Row, Select, Space } from 'antd'; import { debounce } from 'lodash-es'; import { useEffect, useState } from 'react'; @@ -6,21 +6,14 @@ import MonacoEditor from 'react-monaco-editor'; import { InitCode } from '@/components/editor'; import Viewer from '@/components/viewer/viewer'; +import ErrorFmt, { ExportFormat, ImportFormat } from '@/services/dbml'; import { ExportOutlined, ImportOutlined } from '@ant-design/icons'; import { PageContainer } from '@ant-design/pro-components'; import { CompilerError } from '@dbml/core/types/parse/error'; import TextArea from 'antd/es/input/TextArea'; import './index.less'; -type ImportFormat = - | 'dbml' - | 'mysql' - | 'postgres' - | 'json' - | 'mssql' - | 'postgresLegacy'; - -type ExportFormat = 'dbml' | 'mysql' | 'postgres' | 'json' | 'mssql' | 'oracle'; +const defaultBuildDelay = 2000; export default () => { const [messageApi, contextHolder] = message.useMessage(); @@ -39,40 +32,18 @@ export default () => { const [exportText, setExportText] = useState(''); const [regen, setRegen] = useState(0); - // editorDidMount + // editor init const editorDidMount = () => { setDatabase(initialDatabase); }; - // code change - useEffect(() => { - try { - const newDB = parser.parse(code, 'dbmlv2'); - setDatabase(newDB); - } catch (e) { - if (e as CompilerError) { - const diags = (e as CompilerError).diags - .map((d: CompilerDiagnostic) => { - return `${d.location.start.line}:${d.location.start.column} ${d.message}`; - }) - .join('\n'); - - messageApi.error(diags); - // TODO hl to editor - } else if (e instanceof Error) { - messageApi.error(`${e.message}`); - } else { - throw e; - } - } - }, [code]); - // editor change const editorOnChange = (newValue: any) => { setCode(newValue); }; - const debouncedOnChange = debounce(editorOnChange, 500); + const debouncedOnChange = debounce(editorOnChange, defaultBuildDelay); + // handle import const handleImport = () => { try { const s = importer.import(importText, importFormat); @@ -80,13 +51,7 @@ export default () => { setIsImportModalOpen(false); } catch (e) { if (e as CompilerError) { - const diags = (e as CompilerError).diags - .map((d: CompilerDiagnostic) => { - return `${d.location.start.line}:${d.location.start.column} ${d.message}`; - }) - .join('\n'); - - messageApi.error(diags); + messageApi.error(ErrorFmt(e as CompilerError)); } else if (e instanceof Error) { messageApi.error(`${e.message}`); return; @@ -96,6 +61,24 @@ export default () => { } }; + // code change regen database + useEffect(() => { + try { + const newDB = parser.parse(code, 'dbmlv2'); + setDatabase(newDB); + } catch (e) { + if (e as CompilerError) { + messageApi.error(ErrorFmt(e as CompilerError)); + // TODO hl to editor + } else if (e instanceof Error) { + messageApi.error(`${e.message}`); + } else { + throw e; + } + } + }, [code]); + + // export regen useEffect(() => { if (!isExportModalOpen) return; @@ -104,13 +87,7 @@ export default () => { setExportText(s); } catch (e) { if (e as CompilerError) { - const diags = (e as CompilerError).diags - .map((d: CompilerDiagnostic) => { - return `${d.location.start.line}:${d.location.start.column} ${d.message}`; - }) - .join('\n'); - - messageApi.error(diags); + messageApi.error(ErrorFmt(e as CompilerError)); } else if (e instanceof Error) { messageApi.error(`${e.message}`); } else { diff --git a/src/services/dbml/index.ts b/src/services/dbml/index.ts new file mode 100644 index 0000000..fc39b87 --- /dev/null +++ b/src/services/dbml/index.ts @@ -0,0 +1,22 @@ +import { CompilerDiagnostic } from '@dbml/core'; +import { CompilerError } from '@dbml/core/types/parse/error'; + +type ImportFormat = + | 'dbml' + | 'mysql' + | 'postgres' + | 'json' + | 'mssql' + | 'postgresLegacy'; +type ExportFormat = 'dbml' | 'mysql' | 'postgres' | 'json' | 'mssql' | 'oracle'; + +export default function ErrorFmt(e: CompilerError): string { + const diags = e.diags + .map((d: CompilerDiagnostic) => { + return `${d.location.start.line}:${d.location.start.column} ${d.message}`; + }) + .join('\n'); + return diags; +} + +export type { ExportFormat, ImportFormat }; diff --git a/src/editor/syntax.ts b/src/services/editor/syntax.ts similarity index 94% rename from src/editor/syntax.ts rename to src/services/editor/syntax.ts index e844025..91cf950 100644 --- a/src/editor/syntax.ts +++ b/src/services/editor/syntax.ts @@ -138,6 +138,7 @@ function registerSyntax() { { include: '@whitespace' }, // delimiters and operators + // eslint-disable-next-line no-useless-escape [/[\[\]{}().,;]/, '@brackets'], [ /@symbols/, @@ -150,6 +151,7 @@ function registerSyntax() { ], // numbers + // eslint-disable-next-line no-useless-escape [/\d*\.\d+([eE][\-+]?\d+)?/, 'number.float'], [/0[xX][0-9a-fA-F]+/, 'number.hex'], [/\d+/, 'number'], @@ -165,8 +167,10 @@ function registerSyntax() { ], comment: [ + // eslint-disable-next-line no-useless-escape [/[^\/*]+/, 'comment'], [/\*\//, 'comment', '@pop'], + // eslint-disable-next-line no-useless-escape [/[\/*]/, 'comment'], ], diff --git a/src/parser/parser.ts b/src/services/er/index.ts similarity index 100% rename from src/parser/parser.ts rename to src/services/er/index.ts