From 41afb834aefa5fcd52153145b17d4898dec156e0 Mon Sep 17 00:00:00 2001 From: landaiqing Date: Fri, 12 Sep 2025 00:52:19 +0800 Subject: [PATCH] :sparkles: Added sql prettier plugin --- frontend/package-lock.json | 83 +- frontend/package.json | 1 + .../src/utils/prettier/plugins/sql/detect.mjs | 1180 +++++++++++++++++ .../src/utils/prettier/plugins/sql/sql.d.ts | 11 + .../src/utils/prettier/plugins/sql/sql.mjs | 60 + .../codeblock/lang-parser/languages.ts | 11 +- 6 files changed, 1342 insertions(+), 4 deletions(-) create mode 100644 frontend/src/utils/prettier/plugins/sql/detect.mjs create mode 100644 frontend/src/utils/prettier/plugins/sql/sql.d.ts create mode 100644 frontend/src/utils/prettier/plugins/sql/sql.mjs diff --git a/frontend/package-lock.json b/frontend/package-lock.json index fbc3e3f..90a2d59 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -51,6 +51,7 @@ "prettier": "^3.6.2", "remarkable": "^2.0.1", "sass": "^1.92.1", + "sql-formatter": "^15.6.9", "vue": "^3.5.21", "vue-i18n": "^11.1.12", "vue-pick-colors": "^1.8.0", @@ -2700,7 +2701,6 @@ "version": "2.0.1", "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, "license": "Python-2.0" }, "node_modules/autolinker": { @@ -2933,6 +2933,12 @@ "url": "https://jaywcjlove.github.io/#/sponsor" } }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", @@ -3076,6 +3082,12 @@ "node": ">=0.10" } }, + "node_modules/discontinuous-range": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/discontinuous-range/-/discontinuous-range-1.0.0.tgz", + "integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==", + "license": "MIT" + }, "node_modules/dotenv": { "version": "16.5.0", "resolved": "https://registry.npmmirror.com/dotenv/-/dotenv-16.5.0.tgz", @@ -3958,6 +3970,12 @@ "pathe": "^2.0.1" } }, + "node_modules/moo": { + "version": "0.5.2", + "resolved": "https://registry.npmmirror.com/moo/-/moo-0.5.2.tgz", + "integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==", + "license": "BSD-3-Clause" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", @@ -4007,6 +4025,28 @@ "dev": true, "license": "MIT" }, + "node_modules/nearley": { + "version": "2.20.1", + "resolved": "https://registry.npmmirror.com/nearley/-/nearley-2.20.1.tgz", + "integrity": "sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==", + "license": "MIT", + "dependencies": { + "commander": "^2.19.0", + "moo": "^0.5.0", + "railroad-diagrams": "^1.0.0", + "randexp": "0.4.6" + }, + "bin": { + "nearley-railroad": "bin/nearley-railroad.js", + "nearley-test": "bin/nearley-test.js", + "nearley-unparse": "bin/nearley-unparse.js", + "nearleyc": "bin/nearleyc.js" + }, + "funding": { + "type": "individual", + "url": "https://nearley.js.org/#give-to-nearley" + } + }, "node_modules/node-addon-api": { "version": "7.1.1", "resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-7.1.1.tgz", @@ -4371,6 +4411,25 @@ ], "license": "MIT" }, + "node_modules/railroad-diagrams": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz", + "integrity": "sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==", + "license": "CC0-1.0" + }, + "node_modules/randexp": { + "version": "0.4.6", + "resolved": "https://registry.npmmirror.com/randexp/-/randexp-0.4.6.tgz", + "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==", + "license": "MIT", + "dependencies": { + "discontinuous-range": "1.0.0", + "ret": "~0.1.10" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/rc9": { "version": "2.1.2", "resolved": "https://registry.npmmirror.com/rc9/-/rc9-2.1.2.tgz", @@ -4431,6 +4490,15 @@ "node": ">=4" } }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmmirror.com/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "license": "MIT", + "engines": { + "node": ">=0.12" + } + }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmmirror.com/reusify/-/reusify-1.1.0.tgz", @@ -4600,6 +4668,19 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "license": "BSD-3-Clause" }, + "node_modules/sql-formatter": { + "version": "15.6.9", + "resolved": "https://registry.npmmirror.com/sql-formatter/-/sql-formatter-15.6.9.tgz", + "integrity": "sha512-r9VKnkRfKW7jbhTgytwbM+JqmFclQYN9L58Z3UTktuy9V1f1Y+rGK3t70Truh2wIOJzvZkzobAQ2PwGjjXsr6Q==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "nearley": "^2.20.1" + }, + "bin": { + "sql-formatter": "bin/sql-formatter-cli.cjs" + } + }, "node_modules/std-env": { "version": "3.9.0", "resolved": "https://registry.npmmirror.com/std-env/-/std-env-3.9.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 516d82e..f315702 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -55,6 +55,7 @@ "prettier": "^3.6.2", "remarkable": "^2.0.1", "sass": "^1.92.1", + "sql-formatter": "^15.6.9", "vue": "^3.5.21", "vue-i18n": "^11.1.12", "vue-pick-colors": "^1.8.0", diff --git a/frontend/src/utils/prettier/plugins/sql/detect.mjs b/frontend/src/utils/prettier/plugins/sql/detect.mjs new file mode 100644 index 0000000..297e306 --- /dev/null +++ b/frontend/src/utils/prettier/plugins/sql/detect.mjs @@ -0,0 +1,1180 @@ +// SQL方言特征检测规则 +const dialectPatterns = { + mysql: [ + /\bAUTO_INCREMENT\b/i, + /\bENGINE\s*=/i, + /\bCHARSET\s*=/i, + /\bCOLLATE\s*=/i, + /\bLIMIT\s+\d+\s*OFFSET\s+\d+/i, + /\bUNSIGNED\b/i, + /\bTINYINT\b/i, + /\bMEDIUMINT\b/i, + /\bBIGINT\b/i, + /\bTEXT\b/i, + /\bLONGTEXT\b/i, + /\bMEDIUMTEXT\b/i, + /\bTINYTEXT\b/i, + /\bENUM\s*\(/i, + /\bSET\s*\(/i, + /\bIF\s*\(/i, + /\bIFNULL\s*\(/i, + /\bCONCAT\s*\(/i, + /\bGROUP_CONCAT\s*\(/i, + /\bDATE_FORMAT\s*\(/i, + /\bSTR_TO_DATE\s*\(/i, + /\bUNIX_TIMESTAMP\s*\(/i, + /\bFROM_UNIXTIME\s*\(/i, + /\bINSERT\s+IGNORE\b/i, + /\bREPLACE\s+INTO\b/i, + /\bON\s+DUPLICATE\s+KEY\s+UPDATE\b/i + ], + + postgresql: [ + /\bSERIAL\b/i, + /\bBIGSERIAL\b/i, + /\bSMALLSERIAL\b/i, + /\bBOOLEAN\b/i, + /\bTEXT\[\]/i, + /\bINTEGER\[\]/i, + /\bJSONB\b/i, + /\bUUID\b/i, + /\bINET\b/i, + /\bCIDR\b/i, + /\bMACaddr\b/i, + /\bTSVECTOR\b/i, + /\bTSQUERY\b/i, + /\bPOINT\b/i, + /\bLINE\b/i, + /\bLSEG\b/i, + /\bBOX\b/i, + /\bPATH\b/i, + /\bPOLYGON\b/i, + /\bCIRCLE\b/i, + /\bLIMIT\s+\d+\s+OFFSET\s+\d+/i, + /\bRETURNING\b/i, + /\bON\s+CONFLICT\b/i, + /\bDO\s+NOTHING\b/i, + /\bDO\s+UPDATE\s+SET\b/i, + /\bFETCH\s+FIRST\b/i, + /\bFETCH\s+NEXT\b/i, + /\bROWS\s+ONLY\b/i, + /\bWITH\s+RECURSIVE\b/i, + /\bARRAY\s*\[/i, + /\bUNNEST\s*\(/i, + /\bSTRING_AGG\s*\(/i, + /\bEXTRACT\s*\(/i, + /\bGENERATE_SERIES\s*\(/i, + /\bCOALESCE\s*\(/i, + /\bNULLIF\s*\(/i, + /\bAGE\s*\(/i, + /\bNOW\s*\(\s*\)/i, + /\bCURRENT_TIMESTAMP\b/i, + /\bCURRENT_DATE\b/i, + /\bCURRENT_TIME\b/i, + /\bINTERVAL\s+'/i, + /\bREGEXP_REPLACE\s*\(/i, + /\bREGEXP_SPLIT_TO_ARRAY\s*\(/i, + /\b\$\$[^$]*\$\$/i, + /\bCREATE\s+EXTENSION\b/i, + /\bCREATE\s+OR\s+REPLACE\s+FUNCTION\b/i, + /\bCREATE\s+OR\s+REPLACE\s+VIEW\b/i, + /\bPLPGSQL\b/i, + /\bTABLESPACE\b/i, + /\bSCHEMA\b/i + ], + + sqlite: [ + /\bPRAGMA\b/i, + /\bAUTOINCREMENT\b/i, + /\bWITHOUT\s+ROWID\b/i, + /\bSTRICT\b/i, + /\bIF\s+NOT\s+EXISTS\b/i, + /\bREPLACE\b/i, + /\bVACUUM\b/i, + /\bREINDEX\b/i, + /\bANALYZE\b/i, + /\bATTACH\s+DATABASE\b/i, + /\bDETACH\s+DATABASE\b/i, + /\bTEMP\b/i, + /\bTEMPORARY\b/i, + /\bBEGIN\s+IMMEDIATE\b/i, + /\bBEGIN\s+EXCLUSIVE\b/i, + /\bEXPLAIN\s+QUERY\s+PLAN\b/i, + /\bRANDOM\s*\(\s*\)/i, + /\bLENGTH\s*\(/i, + /\bSUBSTR\s*\(/i, + /\bREPLACE\s*\(/i, + /\bTRIM\s*\(/i, + /\bLTRIM\s*\(/i, + /\bRTRIM\s*\(/i, + /\bUPPER\s*\(/i, + /\bLOWER\s*\(/i, + /\bINSTR\s*\(/i, + /\bROUND\s*\(/i, + /\bABS\s*\(/i, + /\bMAX\s*\(/i, + /\bMIN\s*\(/i, + /\bDATE\s*\(/i, + /\bTIME\s*\(/i, + /\bDATETIME\s*\(/i, + /\bJULIANDAY\s*\(/i, + /\bSTRFTIME\s*\(/i, + /\bGLOB\s*\(/i, + /\bLIKE\s*\(/i, + /\bCAST\s*\(/i, + /\bTYPEOF\s*\(/i + ], + + transactsql: [ + /\bIDENTITY\s*\(/i, + /\bUNIQUEIDENTIFIER\b/i, + /\bNVARCHAR\b/i, + /\bNTEXT\b/i, + /\bNUMERIC\b/i, + /\bSMALLDATETIME\b/i, + /\bDATETIME2\b/i, + /\bDATETIMEOFFSET\b/i, + /\bTIME\b/i, + /\bIMAGE\b/i, + /\bMONEY\b/i, + /\bSMALLMONEY\b/i, + /\bSQL_VARIANT\b/i, + /\bTABLE\b/i, + /\bXML\b/i, + /\bGEOMETRY\b/i, + /\bGEOGRAPHY\b/i, + /\bTOP\s+\d+/i, + /\bPERCENT\b/i, + /\bWITH\s+TIES\b/i, + /\bOFFSET\s+\d+\s+ROWS/i, + /\bFETCH\s+NEXT\s+\d+\s+ROWS\s+ONLY/i, + /\bISNULL\s*\(/i, + /\bCONVERT\s*\(/i, + /\bCAST\s*\(/i, + /\bDATEDIFF\s*\(/i, + /\bDATEADD\s*\(/i, + /\bDATEPART\s*\(/i, + /\bGETDATE\s*\(\s*\)/i, + /\bGETUTCDATE\s*\(\s*\)/i, + /\bSYSDATETIME\s*\(\s*\)/i, + /\bSYSUTCDATETIME\s*\(\s*\)/i, + /\bCURRENT_TIMESTAMP\b/i, + /\bLEN\s*\(/i, + /\bLEFT\s*\(/i, + /\bRIGHT\s*\(/i, + /\bCHARINDEX\s*\(/i, + /\bPATINDEX\s*\(/i, + /\bSTUFF\s*\(/i, + /\bREVERSE\s*\(/i, + /\bREPLICATE\s*\(/i, + /\bSPACE\s*\(/i, + /\bSTR\s*\(/i, + /\bFORMAT\s*\(/i, + /\bPARSENAME\s*\(/i, + /\bQUOTENAME\s*\(/i, + /\bMERGE\b/i, + /\bWHEN\s+MATCHED\b/i, + /\bWHEN\s+NOT\s+MATCHED\b/i, + /\bUSING\b/i, + /\bOUTPUT\b/i, + /\bINSERTED\b/i, + /\bDELETED\b/i, + /\bTRUNCATE\s+TABLE\b/i, + /\bEXEC\b/i, + /\bEXECUTE\b/i, + /\bSP_EXECUTESQL\b/i, + /\bBEGIN\s+TRAN\b/i, + /\bCOMMIT\s+TRAN\b/i, + /\bROLLBACK\s+TRAN\b/i, + /\bSAVE\s+TRAN\b/i, + /\bTRY\b/i, + /\bCATCH\b/i, + /\bTHROW\b/i, + /\bRAISERROR\b/i, + /\bPRINT\b/i, + /\bSET\s+NOCOUNT\s+ON\b/i, + /\bSET\s+ANSI_NULLS\s+ON\b/i, + /\bSET\s+QUOTED_IDENTIFIER\s+ON\b/i, + /\bWITH\s+\(\s*NOLOCK\s*\)/i, + /\bROW_NUMBER\s*\(\s*\)\s+OVER\s*\(/i, + /\bRANK\s*\(\s*\)\s+OVER\s*\(/i, + /\bDENSE_RANK\s*\(\s*\)\s+OVER\s*\(/i, + /\bNTILE\s*\(/i, + /\bLAG\s*\(/i, + /\bLEAD\s*\(/i, + /\bFIRST_VALUE\s*\(/i, + /\bLAST_VALUE\s*\(/i, + /\bCTE\b/i, + /\bPIVOT\b/i, + /\bUNPIVOT\b/i, + /\bAPPLY\b/i, + /\bOUTER\s+APPLY\b/i, + /\bCROSS\s+APPLY\b/i + ], + + bigquery: [ + /\bSTRUCT\s*/i, + /\bBEFORE\s*\(\s*TIMESTAMP\s*=>/i, + /\bQUALIFY\b/i, + /\bMINUS\b/i, + /\bCONCAT\s*\(/i, + /\bCONCAT_WS\s*\(/i, + /\bSPLIT\s*\(/i, + /\bSPLIT_PART\s*\(/i, + /\bSTARTSWITH\s*\(/i, + /\bENDSWITH\s*\(/i, + /\bCONTAINS\s*\(/i, + /\bTRY_CAST\s*\(/i, + /\bTRY_TO_NUMBER\s*\(/i, + /\bTRY_TO_DECIMAL\s*\(/i, + /\bTRY_TO_DATE\s*\(/i, + /\bTRY_TO_TIME\s*\(/i, + /\bTRY_TO_TIMESTAMP\s*\(/i, + /\bTRY_TO_BINARY\s*\(/i, + /\bPARSE_JSON\s*\(/i, + /\bPARSE_XML\s*\(/i, + /\bTRY_PARSE_JSON\s*\(/i, + /\bCHECK_JSON\s*\(/i, + /\bCHECK_XML\s*\(/i, + /\bSTRIP_NULL_VALUE\s*\(/i, + /\bOBJECT_CONSTRUCT\s*\(/i, + /\bOBJECT_CONSTRUCT_KEEP_NULL\s*\(/i, + /\bOBJECT_DELETE\s*\(/i, + /\bOBJECT_INSERT\s*\(/i, + /\bOBJECT_PICK\s*\(/i, + /\bARRAY_CONSTRUCT\s*\(/i, + /\bARRAY_CONSTRUCT_COMPACT\s*\(/i, + /\bARRAY_APPEND\s*\(/i, + /\bARRAY_CAT\s*\(/i, + /\bARRAY_COMPACT\s*\(/i, + /\bARRAY_CONTAINS\s*\(/i, + /\bARRAY_DISTINCT\s*\(/i, + /\bARRAY_EXCEPT\s*\(/i, + /\bARRAY_FLATTEN\s*\(/i, + /\bARRAY_GENERATE_RANGE\s*\(/i, + /\bARRAY_INSERT\s*\(/i, + /\bARRAY_INTERSECTION\s*\(/i, + /\bARRAY_POSITION\s*\(/i, + /\bARRAY_PREPEND\s*\(/i, + /\bARRAY_REMOVE\s*\(/i, + /\bARRAY_REMOVE_AT\s*\(/i, + /\bARRAY_SIZE\s*\(/i, + /\bARRAY_SLICE\s*\(/i, + /\bARRAY_SORT\s*\(/i, + /\bARRAY_TO_STRING\s*\(/i, + /\bARRAY_UNION\s*\(/i, + /\bARRAY_UNIQUE_AGG\s*\(/i, + /\bGET\s*\(/i, + /\bGET_PATH\s*\(/i, + /\bFLATTEN\s*\(/i, + /\bCURRENT_AVAILABLE_ROLES\s*\(\s*\)/i, + /\bCURRENT_CLIENT\s*\(\s*\)/i, + /\bCURRENT_DATABASE\s*\(\s*\)/i, + /\bCURRENT_REGION\s*\(\s*\)/i, + /\bCURRENT_ROLE\s*\(\s*\)/i, + /\bCURRENT_SCHEMA\s*\(\s*\)/i, + /\bCURRENT_SCHEMAS\s*\(\s*\)/i, + /\bCURRENT_SESSION\s*\(\s*\)/i, + /\bCURRENT_STATEMENT\s*\(\s*\)/i, + /\bCURRENT_TIME\s*\(\s*\)/i, + /\bCURRENT_TIMESTAMP\s*\(\s*\)/i, + /\bCURRENT_TRANSACTION\s*\(\s*\)/i, + /\bCURRENT_USER\s*\(\s*\)/i, + /\bCURRENT_VERSION\s*\(\s*\)/i, + /\bCURRENT_WAREHOUSE\s*\(\s*\)/i, + /\bLOCALTIME\s*\(\s*\)/i, + /\bLOCALTIMESTAMP\s*\(\s*\)/i, + /\bSYSDATE\s*\(\s*\)/i, + /\bGETDATE\s*\(\s*\)/i, + /\bLAST_DAY\s*\(/i, + /\bNEXT_DAY\s*\(/i, + /\bPREVIOUS_DAY\s*\(/i, + /\bDATE_FROM_PARTS\s*\(/i, + /\bTIME_FROM_PARTS\s*\(/i, + /\bTIMESTAMP_FROM_PARTS\s*\(/i, + /\bDAYNAME\s*\(/i, + /\bMONTHNAME\s*\(/i, + /\bQUARTER\s*\(/i, + /\bYEAROFWEEK\s*\(/i, + /\bYEAROFWEEKISO\s*\(/i, + /\bWEEKOFYEAR\s*\(/i, + /\bWEEKISO\s*\(/i, + /\bDAYOFWEEK\s*\(/i, + /\bDAYOFWEEKISO\s*\(/i, + /\bDAYOFYEAR\s*\(/i, + /\bHOUR\s*\(/i, + /\bMINUTE\s*\(/i, + /\bSECOND\s*\(/i, + /\bNANOSECOND\s*\(/i, + /\bEPOCH_SECOND\s*\(/i, + /\bEPOCH_MILLISECOND\s*\(/i, + /\bEPOCH_MICROSECOND\s*\(/i, + /\bEPOCH_NANOSECOND\s*\(/i, + /\bTIMEZONE_HOUR\s*\(/i, + /\bTIMEZONE_MINUTE\s*\(/i, + /\bISO_WEEK_START\s*\(/i, + /\bISO_WEEK_END\s*\(/i, + /\bWEEK_START\s*\(/i, + /\bWEEK_END\s*\(/i, + /\bISO_YEAR_START\s*\(/i, + /\bISO_YEAR_END\s*\(/i, + /\bYEAR_START\s*\(/i, + /\bYEAR_END\s*\(/i, + /\bCONVERT_TIMEZONE\s*\(/i, + /\bIFF\s*\(/i, + /\bZEROIFNULL\s*\(/i, + /\bNULLIFZERO\s*\(/i, + /\bEQUAL_NULL\s*\(/i, + /\bBOOLAND\s*\(/i, + /\bBOOLOR\s*\(/i, + /\bBOOLXOR\s*\(/i, + /\bBOOLNOT\s*\(/i, + /\bMODE\s*\(/i, + /\bUNIFORM\s*\(/i, + /\bNORMAL\s*\(/i, + /\bSEQ1\s*\(\s*\)/i, + /\bSEQ2\s*\(\s*\)/i, + /\bSEQ4\s*\(\s*\)/i, + /\bSEQ8\s*\(\s*\)/i, + /\bUUID_STRING\s*\(\s*\)/i, + /\bRANDOM\s*\(\s*\)/i, + /\bRRANDOM\s*\(/i, + /\bZIPF\s*\(/i, + /\bHASH\s*\(/i, + /\bSHA1\s*\(/i, + /\bSHA1_HEX\s*\(/i, + /\bSHA1_BINARY\s*\(/i, + /\bSHA2\s*\(/i, + /\bSHA2_HEX\s*\(/i, + /\bSHA2_BINARY\s*\(/i, + /\bMD5\s*\(/i, + /\bMD5_HEX\s*\(/i, + /\bMD5_BINARY\s*\(/i, + /\bMD5_NUMBER\s*\(/i, + /\bMD5_NUMBER_LOWER64\s*\(/i, + /\bMD5_NUMBER_UPPER64\s*\(/i, + /\bBASE64_ENCODE\s*\(/i, + /\bBASE64_DECODE_STRING\s*\(/i, + /\bBASE64_DECODE_BINARY\s*\(/i, + /\bHEX_ENCODE\s*\(/i, + /\bHEX_DECODE_STRING\s*\(/i, + /\bHEX_DECODE_BINARY\s*\(/i, + /\bTRY_BASE64_DECODE_STRING\s*\(/i, + /\bTRY_BASE64_DECODE_BINARY\s*\(/i, + /\bTRY_HEX_DECODE_STRING\s*\(/i, + /\bTRY_HEX_DECODE_BINARY\s*\(/i, + /\bCOMPRESS\s*\(/i, + /\bDECOMPRESS_STRING\s*\(/i, + /\bDECOMPRESS_BINARY\s*\(/i + ], + + mariadb: [ + // MariaDB specific features (extends MySQL) + /\bSEQUENCE\b/i, + /\bROLE\b/i, + /\bCOLUMN_CHECK\s*\(/i, + /\bCOLUMN_GET\s*\(/i, + /\bCOLUMN_JSON\s*\(/i, + /\bDYNAMIC_COLUMN_\w+\s*\(/i, + /\bJSON_ARRAY\s*\(/i, + /\bJSON_ARRAYAGG\s*\(/i, + /\bJSON_OBJECT\s*\(/i, + /\bJSON_OBJECTAGG\s*\(/i, + /\bJSON_EXTRACT\s*\(/i, + /\bJSON_UNQUOTE\s*\(/i, + /\bJSON_VALID\s*\(/i, + /\bGIS\b/i, + /\bSPIDER\b/i, + /\bCONNECT\s+ENGINE\b/i, + /\bFEDERATEDX\b/i, + /\bCONNECTION\s*=/i, + /\bVIRTUAL\s+COLUMN\b/i, + /\bSTORED\s+COLUMN\b/i, + /\bGENERATED\s+ALWAYS\b/i, + /\bAUTO_INCREMENT\b/i, + /\bENGINE\s*=/i, + /\bCHARSET\s*=/i, + /\bCOLLATE\s*=/i + ], + + db2: [ + // IBM DB2 specific features + /\bIDENTITY\s*\(\s*START\s+WITH\b/i, + /\bGENERATED\s+ALWAYS\b/i, + /\bGENERATED\s+BY\s+DEFAULT\b/i, + /\bDECLARE\s+GLOBAL\s+TEMPORARY\s+TABLE\b/i, + /\bFINAL\s+TABLE\b/i, + /\bNEW\s+TABLE\b/i, + /\bOLD\s+TABLE\b/i, + /\bDECFLOAT\b/i, + /\bBIGINT\b/i, + /\bSMALLINT\b/i, + /\bREAL\b/i, + /\bDOUBLE\b/i, + /\bGRAPHIC\s*\(/i, + /\bVARGRAPHIC\s*\(/i, + /\bDBCLOB\s*\(/i, + /\bXML\b/i, + /\bROWID\b/i, + /\bDATE\b/i, + /\bTIME\b/i, + /\bTIMESTAMP\b/i, + /\bVALUES\s+NEXTVAL\s+FOR\b/i, + /\bVALUES\s+PREVVAL\s+FOR\b/i, + /\bFETCH\s+FIRST\s+\d+\s+ROWS\s+ONLY\b/i, + /\bFETCH\s+NEXT\s+\d+\s+ROWS\s+ONLY\b/i, + /\bROW\s+CHANGE\s+TIMESTAMP\b/i, + /\bROW\s+BEGIN\b/i, + /\bROW\s+END\b/i, + /\bSYSTEM_TIME\b/i, + /\bBUSINESS_TIME\b/i, + /\bVERSIONING\b/i, + /\bWITH\s+ORDINALITY\b/i, + /\bLATERAL\b/i, + /\bOVER\s*\(\s*PARTITION\s+BY\b/i, + /\bRANKING\b/i, + /\bAGGREGATION\b/i, + /\bNUMBERING\b/i + ], + + db2i: [ + // IBM DB2 for i specific features (AS/400) + /\bAS\/400\b/i, + /\biSeries\b/i, + /\bSYSTEM\s+i\b/i, + /\bQSYS\b/i, + /\bQTEMP\b/i, + /\bRCDFMT\b/i, + /\bDATA\s+AREA\b/i, + /\bJOURNAL\b/i, + /\bJRNL\b/i, + /\bLIBRARY\b/i, + /\bSCHEMA\b/i, + /\bCOLLECTION\b/i, + /\bMEMBER\b/i, + /\bFILE\b/i, + /\bRECORD\b/i, + /\bFIELD\b/i, + /\bKEYWORD\b/i, + /\bVALUES\b/i, + /\bRUNSQLSTM\b/i, + /\bSTRSQL\b/i, + /\bINTERACTIVE\s+SQL\b/i, + /\bSQL\s+REQUEST\b/i, + /\bSQL\s+PACKAGE\b/i, + /\bBINDING\b/i, + /\bACCESS\s+PLAN\b/i, + /\bOPTIMIZATION\b/i, + /\bSTAT_VIEW\b/i, + /\bMQT\b/i, + /\bMATERIALIZED\s+QUERY\s+TABLE\b/i, + /\bREFRESH\s+DEFERRED\b/i, + /\bREFRESH\s+IMMEDIATE\b/i, + /\bENABLE\s+QUERY\s+OPTIMIZATION\b/i, + /\bDISABLE\s+QUERY\s+OPTIMIZATION\b/i + ], + + hive: [ + // Apache Hive specific features + /\bPARTITIONED\s+BY\b/i, + /\bCLUSTERED\s+BY\b/i, + /\bSORTED\s+BY\b/i, + /\bINTO\s+\d+\s+BUCKETS\b/i, + /\bSTORED\s+AS\s+ORC\b/i, + /\bSTORED\s+AS\s+PARQUET\b/i, + /\bSTORED\s+AS\s+AVRO\b/i, + /\bSTORED\s+AS\s+RCFILE\b/i, + /\bSTORED\s+AS\s+SEQUENCEFILE\b/i, + /\bSTORED\s+AS\s+TEXTFILE\b/i, + /\bROW\s+FORMAT\s+SERDE\b/i, + /\bINPUTFORMAT\b/i, + /\bOUTPUTFORMAT\b/i, + /\bLOCATION\s+'/i, + /\bTBLPROPERTIES\s*\(/i, + /\bSERDEPROPERTIES\s*\(/i, + /\bADD\s+JAR\b/i, + /\bADD\s+FILE\b/i, + /\bADD\s+ARCHIVE\b/i, + /\bTRANSFORM\b/i, + /\bUSING\s+'/i, + /\bAS\s+\(/i, + /\bLATERAL\s+VIEW\b/i, + /\bEXPLODE\s*\(/i, + /\bPOSEXPLODE\s*\(/i, + /\bINLINE\s*\(/i, + /\bSTACK\s*\(/i, + /\bJSON_TUPLE\s*\(/i, + /\bPARSE_URL\s*\(/i, + /\bPARSE_URL_TUPLE\s*\(/i, + /\bXPATH\s*\(/i, + /\bXPATH_STRING\s*\(/i, + /\bXPATH_BOOLEAN\s*\(/i, + /\bXPATH_NUMBER\s*\(/i, + /\bXPATH_DOUBLE\s*\(/i, + /\bXPATH_FLOAT\s*\(/i, + /\bXPATH_INT\s*\(/i, + /\bXPATH_LONG\s*\(/i, + /\bXPATH_SHORT\s*\(/i, + /\bGET_JSON_OBJECT\s*\(/i, + /\bSTR_TO_MAP\s*\(/i, + /\bSENTENCES\s*\(/i, + /\bNGRAMS\s*\(/i, + /\bCONTEXT_NGRAMS\s*\(/i, + /\bWORDCOUNT\s*\(/i, + /\bCOLLECT_LIST\s*\(/i, + /\bCOLLECT_SET\s*\(/i, + /\bHISTOGRAM_NUMERIC\s*\(/i, + /\bPERCENTILE\s*\(/i, + /\bPERCENTILE_APPROX\s*\(/i, + /\bUDTF\b/i, + /\bUDAF\b/i, + /\bUDF\b/i, + /\bMAP\s* highestScore) { + bestDialect = dialect; + highestScore = score; + } + } + + // 如果没有明显的特征,尝试通用检测 + if (highestScore === 0) { + return detectGenericFeatures(normalizedSql); + } + + return bestDialect; +} + +/** + * 通用特征检测 + * @param {string} sql - SQL语句 + * @returns {string} - 检测到的SQL方言 + */ +function detectGenericFeatures(sql) { + const upperSql = sql.toUpperCase(); + + // 检测一些通用但有倾向性的特征 + if (upperSql.includes('LIMIT') && upperSql.includes('OFFSET')) { + if (upperSql.includes('AUTO_INCREMENT') || upperSql.includes('ENGINE=')) { + return 'mysql'; + } + return 'postgresql'; + } + + if (upperSql.includes('TOP ') && (upperSql.includes('IDENTITY') || upperSql.includes('NVARCHAR'))) { + return 'transactsql'; + } + + if (upperSql.includes('ROWNUM') || upperSql.includes('DUAL')) { + return 'plsql'; + } + + if (upperSql.includes('PRAGMA') || upperSql.includes('AUTOINCREMENT')) { + return 'sqlite'; + } + + if (upperSql.includes('STRUCT<') || upperSql.includes('ARRAY<')) { + return 'bigquery'; + } + + if (upperSql.includes('VARIANT') || upperSql.includes('$1') || upperSql.includes('QUALIFY')) { + return 'snowflake'; + } + + if (upperSql.includes('PARTITIONED BY') || upperSql.includes('STORED AS ORC') || upperSql.includes('LATERAL VIEW')) { + return 'hive'; + } + + if (upperSql.includes('USE KEYS') || upperSql.includes('UNNEST') && upperSql.includes('SATISFIES')) { + return 'n1ql'; + } + + if (upperSql.includes('DISTSTYLE') || upperSql.includes('SORTKEY') || upperSql.includes('DISTKEY')) { + return 'redshift'; + } + + if (upperSql.includes('COLUMNSTORE') || upperSql.includes('SHARD KEY') || upperSql.includes('REFERENCE TABLE')) { + return 'singlestoredb'; + } + + if (upperSql.includes('CACHE TABLE') || upperSql.includes('BROADCAST(') || upperSql.includes('USING DELTA')) { + return 'spark'; + } + + if (upperSql.includes('TIDB_VERSION') || upperSql.includes('AUTO_RANDOM') || upperSql.includes('AS OF TIMESTAMP')) { + return 'tidb'; + } + + if (upperSql.includes('ARRAY[') || upperSql.includes('MAP(') || upperSql.includes('APPROX_DISTINCT')) { + return 'trino'; + } + + if (upperSql.includes('DECFLOAT') || upperSql.includes('GENERATED ALWAYS') || upperSql.includes('FINAL TABLE')) { + return 'db2'; + } + + if (upperSql.includes('QSYS') || upperSql.includes('JOURNAL') || upperSql.includes('AS/400')) { + return 'db2i'; + } + + if (upperSql.includes('JSON_EXTRACT') && (upperSql.includes('ENGINE=') || upperSql.includes('SEQUENCE'))) { + return 'mariadb'; + } + + // 默认返回通用SQL + return 'sql'; +} diff --git a/frontend/src/utils/prettier/plugins/sql/sql.d.ts b/frontend/src/utils/prettier/plugins/sql/sql.d.ts new file mode 100644 index 0000000..5208bac --- /dev/null +++ b/frontend/src/utils/prettier/plugins/sql/sql.d.ts @@ -0,0 +1,11 @@ +import { Parser, Plugin } from "prettier"; + +export declare const languages: Plugin["languages"]; +export declare const parsers: { + sql: Parser; +}; +export declare const printers: Plugin["printers"]; +export declare const options: Plugin["options"]; + +declare const plugin: Plugin; +export default plugin; diff --git a/frontend/src/utils/prettier/plugins/sql/sql.mjs b/frontend/src/utils/prettier/plugins/sql/sql.mjs new file mode 100644 index 0000000..a32b6d4 --- /dev/null +++ b/frontend/src/utils/prettier/plugins/sql/sql.mjs @@ -0,0 +1,60 @@ +import { format } from 'sql-formatter'; +import { detectDialect } from './detect.mjs'; + +// Languages +export const languages = [{ + name: "SQL", + parsers: ["sql"], + extensions: [".sql"] +}]; + +// Parsers +export const parsers = { + sql: { + parse: (text) => text, + astFormat: "sql-format", + locStart: (node) => 0, + locEnd: (node) => node.length + } +}; + +// Printers +export const printers = { + "sql-format": { + print: (path) => { + const text = path.getValue(); + + if (!text || typeof text !== 'string') { + return text; + } + + try { + // 自动检测SQL方言 + const dialect = detectDialect(text); + + // 格式化配置 - 使用固定的最佳实践配置 + const formatOptions = { + language: dialect, + tabWidth: 2, + useTabs: true, + keywordCase: 'upper', + dataTypeCase: 'upper', + functionCase: 'upper', + identifierCase: 'preserve' + }; + + return format(text, formatOptions); + } catch (error) { + return text; + } + } + } +}; + + +// Default export +export default { + languages, + parsers, + printers +}; \ No newline at end of file diff --git a/frontend/src/views/editor/extensions/codeblock/lang-parser/languages.ts b/frontend/src/views/editor/extensions/codeblock/lang-parser/languages.ts index 302acc1..c89bfab 100644 --- a/frontend/src/views/editor/extensions/codeblock/lang-parser/languages.ts +++ b/frontend/src/views/editor/extensions/codeblock/lang-parser/languages.ts @@ -37,6 +37,7 @@ import cssPrettierPlugin from "prettier/plugins/postcss" import markdownPrettierPlugin from "prettier/plugins/markdown" import yamlPrettierPlugin from "prettier/plugins/yaml" import goPrettierPlugin from "@/utils/prettier/plugins/go/go" +import sqlPrettierPlugin from "@/utils/prettier/plugins/sql/sql" import * as prettierPluginEstree from "prettier/plugins/estree"; /** @@ -50,7 +51,8 @@ export class LanguageInfo { public prettier?: { parser: string; plugins: any[]; - }) {} + }) { + } } /** @@ -67,7 +69,10 @@ export const LANGUAGES: LanguageInfo[] = [ parser: "html", plugins: [htmlPrettierPlugin] }), - new LanguageInfo("sql", "SQL", StandardSQL.language.parser), + new LanguageInfo("sql", "SQL", StandardSQL.language.parser, { + parser: "sql", + plugins: [sqlPrettierPlugin] + }), new LanguageInfo("md", "Markdown", markdownLanguage.parser, { parser: "markdown", plugins: [markdownPrettierPlugin] @@ -89,7 +94,7 @@ export const LANGUAGES: LanguageInfo[] = [ plugins: [yamlPrettierPlugin] }), new LanguageInfo("toml", "TOML", StreamLanguage.define(toml).parser), - new LanguageInfo("go", "Go", StreamLanguage.define(go).parser,{ + new LanguageInfo("go", "Go", StreamLanguage.define(go).parser, { parser: "go", plugins: [goPrettierPlugin] }),