commit a0065e01f2c8996d9c8a7956e194c1bea0d5fc72 Author: yupi <592789970@qq.com> Date: Tue May 10 12:22:48 2022 +0800 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..a7cea0b --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["Vue.volar"] +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..30b15e2 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# Vue 3 + TypeScript + Vite + +This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 ` + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..444c6e3 --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "sql-generator", + "private": true, + "version": "0.0.0", + "scripts": { + "dev": "vite", + "build": "vue-tsc --noEmit && vite build", + "preview": "vite preview" + }, + "dependencies": { + "monaco-editor": "^0.33.0", + "sql-formatter": "^4.0.2", + "tdesign-vue-next": "^0.14.1", + "vue": "^3.2.25" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^2.3.1", + "typescript": "^4.5.4", + "vite": "^2.9.7", + "vue-tsc": "^0.34.7" + } +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/public/favicon.ico differ diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 0000000..f63c105 --- /dev/null +++ b/src/App.vue @@ -0,0 +1,104 @@ + + + + + diff --git a/src/env.d.ts b/src/env.d.ts new file mode 100644 index 0000000..aafef95 --- /dev/null +++ b/src/env.d.ts @@ -0,0 +1,8 @@ +/// + +declare module '*.vue' { + import type { DefineComponent } from 'vue' + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types + const component: DefineComponent<{}, {}, any> + export default component +} diff --git a/src/generator/index.ts b/src/generator/index.ts new file mode 100644 index 0000000..5c1e0e7 --- /dev/null +++ b/src/generator/index.ts @@ -0,0 +1,91 @@ +/** + * 生成 SQL + * @param json + */ +export function doGenerateSQL(json: InputJSON): string { + if (!json?.main) { + return ""; + } + const context = json; + const result = replaceParams(context.main, context); + return replaceSubSql(result, context); +} + +/** + * 参数替换(params) + * @param currentNode + * @param context + * @param params 动态参数 + */ +function replaceParams(currentNode: InputJSONValue, context: InputJSON, params?: Record): string { + if (currentNode == null) { + return ""; + } + const sql = currentNode.sql ?? currentNode; + if (!sql) { + return ""; + } + // 动态、静态参数结合,且优先用静态参数 + params = {...(params ?? {}), ...currentNode.params}; + // 无需替换 + if (!params || Object.keys(params).length < 1) { + return sql; + } + let result = sql; + for (const paramsKey in params) { + const replacedKey = `#{${paramsKey}}`; + // 递归解析 + const replacement = replaceSubSql(params[paramsKey], context); + // find and replace + result = result.replaceAll(replacedKey, replacement); + } + return result; +} + +/** + * 替换子 SQL(@xxx) + * @param sql + * @param context + */ +function replaceSubSql(sql: string, context: InputJSON): string { + if (!sql) { + return ""; + } + const regExp = /@([\u4e00-\u9fa5_a-zA-Z0-9]+)\((.*?)\)/; + let result = sql; + result = String(result); + let regExpMatchArray = result.match(regExp); + // 依次替换 + while (regExpMatchArray && regExpMatchArray.length > 2) { + // 找到结果 + const subKey = regExpMatchArray[1]; + // 可用来替换的节点 + const replacementNode = context[subKey]; + // 没有可替换的节点 + if (!replacementNode) { + throw new Error(`${subKey} 不存在`); + } + // 获取要传递的动态参数 + // e.g. "a = b, c = d" + let paramsStr = regExpMatchArray[2]; + if (paramsStr) { + paramsStr = paramsStr.trim(); + } + // e.g. ["a = b", "c = d"] + const singleParamsStrArray = paramsStr.split(','); + // string => object + const params: Record = {}; + for (const singleParamsStr of singleParamsStrArray) { + const keyValueArray = singleParamsStr.split('='); + if (keyValueArray.length < 2) { + continue; + } + const key = keyValueArray[0].trim(); + params[key] = keyValueArray[1].trim(); + } + const replacement = replaceParams(replacementNode, context, params); + result = result.replaceAll(regExpMatchArray[0], replacement); + regExpMatchArray = result.match(regExp); + } + return result; +} \ No newline at end of file diff --git a/src/generator/type.d.ts b/src/generator/type.d.ts new file mode 100644 index 0000000..dd93ed7 --- /dev/null +++ b/src/generator/type.d.ts @@ -0,0 +1,17 @@ +/** + * 输入 JSON + */ +interface InputJSON extends Record { + // 入口文件 + main: InputJSONValue; +} + +/** + * 输入 JSON Value + */ +interface InputJSONValue { + // sql 语句 + sql: string; + // 静态参数 + params?: Record; +} diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..3047cc1 --- /dev/null +++ b/src/main.js @@ -0,0 +1,9 @@ +import { createApp } from 'vue'; +import TDesign from 'tdesign-vue-next'; +import App from './app.vue'; +// 引入组件库全局样式资源 +import 'tdesign-vue-next/es/style/index.css'; +const app = createApp(App); +app.use(TDesign); +app.mount('#app'); +//# sourceMappingURL=main.js.map \ No newline at end of file diff --git a/src/main.js.map b/src/main.js.map new file mode 100644 index 0000000..325e2a4 --- /dev/null +++ b/src/main.js.map @@ -0,0 +1 @@ +{"version":3,"file":"main.js","sourceRoot":"","sources":["main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,OAAO,MAAM,kBAAkB,CAAC;AACvC,OAAO,GAAG,MAAM,WAAW,CAAC;AAE5B,cAAc;AACd,OAAO,qCAAqC,CAAC;AAE7C,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;AAC3B,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AACjB,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC"} \ No newline at end of file diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..7beac30 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,10 @@ +import { createApp } from 'vue'; +import TDesign from 'tdesign-vue-next'; +import App from './app.vue'; + +// 引入组件库全局样式资源 +import 'tdesign-vue-next/es/style/index.css'; + +const app = createApp(App); +app.use(TDesign); +app.mount('#app'); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..bcc4abd --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "esnext", + "useDefineForClassFields": true, + "module": "esnext", + "moduleResolution": "node", + "strict": true, + "jsx": "preserve", + "sourceMap": true, + "resolveJsonModule": true, + "isolatedModules": true, + "esModuleInterop": true, + "lib": ["esnext", "dom"], + "skipLibCheck": true + }, + "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..e993792 --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "composite": true, + "module": "esnext", + "moduleResolution": "node" + }, + "include": ["vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..315212d --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue()] +})