feat: use esbuild to support ts for codegen

This commit is contained in:
Justineo
2023-08-31 22:14:55 +08:00
parent 29bf99420d
commit bd862426ea
3 changed files with 72 additions and 16 deletions

View File

@ -48,6 +48,7 @@
"echarts": "^5.4.3", "echarts": "^5.4.3",
"echarts-gl": "^2.0.9", "echarts-gl": "^2.0.9",
"echarts-liquidfill": "^3.1.0", "echarts-liquidfill": "^3.1.0",
"esbuild-wasm": "^0.19.2",
"eslint": "^7.32.0", "eslint": "^7.32.0",
"eslint-plugin-prettier": "^3.4.1", "eslint-plugin-prettier": "^3.4.1",
"eslint-plugin-vue": "^8.7.1", "eslint-plugin-vue": "^8.7.1",

9
pnpm-lock.yaml generated
View File

@ -79,6 +79,9 @@ devDependencies:
echarts-liquidfill: echarts-liquidfill:
specifier: ^3.1.0 specifier: ^3.1.0
version: 3.1.0(echarts@5.4.3) version: 3.1.0(echarts@5.4.3)
esbuild-wasm:
specifier: ^0.19.2
version: 0.19.2
eslint: eslint:
specifier: ^7.32.0 specifier: ^7.32.0
version: 7.32.0 version: 7.32.0
@ -4235,6 +4238,12 @@ packages:
resolution: {integrity: sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==} resolution: {integrity: sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==}
dev: true dev: true
/esbuild-wasm@0.19.2:
resolution: {integrity: sha512-ak2XIIJKby+Uo3Iqh8wtw4pn2uZcnfLgtcmBHIgkShpun5ZIJsFigWXp7uLt7gXk3QAOCMmv0TSsIxD5qdn+Vw==}
engines: {node: '>=12'}
hasBin: true
dev: true
/escalade@3.1.1: /escalade@3.1.1:
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
engines: {node: '>=6'} engines: {node: '>=6'}

View File

@ -5,7 +5,8 @@ import {
watch, watch,
onBeforeUnmount, onBeforeUnmount,
defineProps, defineProps,
defineEmits defineEmits,
onMounted
} from "vue"; } from "vue";
import { useLocalStorage } from "@vueuse/core"; import { useLocalStorage } from "@vueuse/core";
import "highlight.js/styles/github.css"; import "highlight.js/styles/github.css";
@ -13,6 +14,7 @@ import hljs from "highlight.js/lib/core";
import javascript from "highlight.js/lib/languages/javascript"; import javascript from "highlight.js/lib/languages/javascript";
import typescript from "highlight.js/lib/languages/typescript"; import typescript from "highlight.js/lib/languages/typescript";
import hljsVuePlugin from "@highlightjs/vue-plugin"; import hljsVuePlugin from "@highlightjs/vue-plugin";
import { initialize, transform } from "esbuild-wasm";
import { getImportsFromOption } from "./utils/codegen"; import { getImportsFromOption } from "./utils/codegen";
@ -56,37 +58,76 @@ watch(
} }
setTimeout(() => { setTimeout(() => {
if (initializing.value) {
return;
}
source.value?.focus(); source.value?.focus();
}); });
} }
); );
const initializing = ref(true);
const optionCode = ref(""); const optionCode = ref("");
const transformedCode = ref("");
const transformErrors = ref([]);
onMounted(async () => {
await initialize({
wasmURL: "https://cdn.jsdelivr.net/npm/esbuild-wasm@0.19.2/esbuild.wasm"
});
initializing.value = false;
source.value?.focus();
});
watch(optionCode, async val => {
try {
transformedCode.value = await transform(`(${val})`, { loader: "ts" });
transformErrors.value = [];
} catch (e) {
transformErrors.value = e.errors;
}
});
function formatError(errors) {
return errors
.map(({ text, location: { lineText, line, column, length } }) => {
const digit = Math.ceil(Math.log10(line)) || 1;
lineText = line === 1 ? lineText.slice(1) : lineText;
lineText =
line === optionCode.value.split("\n").length
? lineText.slice(0, -1)
: lineText;
column = line === 1 ? column - 1 : column;
return `/* ${text} */
// ${line} | ${lineText}
// ${" ".repeat(digit)} | ${" ".repeat(column)}${"~".repeat(length)}
`;
})
.join("\n\n");
}
const importCode = computed(() => { const importCode = computed(() => {
if (optionCode.value.trim() === "") { if (optionCode.value.trim() === "") {
return "/* Paste your option code first */"; return "// Paste your option code first";
} }
let option = null; if (transformErrors.value.length) {
try { return formatError(transformErrors.value);
option = JSON.parse(optionCode.value);
} catch (e) {
try {
option = eval(`(${optionCode.value})`);
} catch (e) {
return `/* Unable to parse \`option\` code */
// ${e.message}
`;
}
} }
try { try {
return getImportsFromOption(option, { return getImportsFromOption(eval(transformedCode.value.code), {
renderer: renderer.value, renderer: renderer.value,
...codegenOptions.value ...codegenOptions.value
}); });
} catch (e) { } catch (e) {
return `/* Invalid ECharts option */`; return `/* Invalid ECharts option */
// ${e.message}
`;
} }
}); });
@ -169,7 +210,12 @@ onBeforeUnmount(() => {
ref="source" ref="source"
class="option-code" class="option-code"
v-model="optionCode" v-model="optionCode"
placeholder="Paste your option code here..." :placeholder="
initializing
? 'Initializing...'
: 'Paste your option code (TS/JS literal) here...'
"
:disabled="initializing"
autofocus autofocus
></textarea> ></textarea>
<code-highlight <code-highlight