summaryrefslogtreecommitdiff
path: root/packages/integrations/vue/src/editor.cts
blob: 0b62e899eed3de4a8a89f8abd3bb2a4d93d7e369 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import { parse } from '@vue/compiler-sfc';

export function toTSX(code: string, className: string): string {
	let result = `export default function ${className}__AstroComponent_(_props: Record<string, any>): any {}`;

	// NOTE: As you can expect, using regexes for this is not exactly the most reliable way of doing things
	// However, I couldn't figure out a way to do it using Vue's compiler, I tried looking at how Volar does it, but I
	// didn't really understand everything happening there and it seemed to be pretty Volar-specific. I do believe
	// someone more knowledgeable on Vue's internals could figure it out, but since this solution is good enough for most
	// Vue components (and it's an improvement over, well, nothing), it's alright, I think
	try {
		const parsedResult = parse(code);

		if (parsedResult.errors.length > 0) {
			return `
				let ${className}__AstroComponent_: Error
				export default ${className}__AstroComponent_
			`;
		}

		// Vue supports 2 type of script blocks: setup and non-setup
		const regularScriptBlockContent = parsedResult.descriptor.script?.content ?? '';
		const { scriptSetup } = parsedResult.descriptor;

		if (scriptSetup) {
			const definePropsType = scriptSetup.content.match(/defineProps<([\S\s]+?)>\s?\(\)/m);
			const propsGeneric = scriptSetup.attrs.generic;
			const propsGenericType = propsGeneric ? `<${propsGeneric}>` : '';

			if (definePropsType) {
				result = `
						${regularScriptBlockContent}
						${scriptSetup.content}

						export default function ${className}__AstroComponent_${propsGenericType}(_props: ${definePropsType[1]}): any {
							<div></div>
						}
				`;
			} else {
				// TODO. Find a way to support generics when using defineProps without passing explicit types.
				// Right now something like this `defineProps({ prop: { type: Array as PropType<T[]> } })`
				//  won't be correctly typed in Astro.
				const defineProps = scriptSetup.content.match(/defineProps\([\s\S]+\)/m);

				if (defineProps) {
					result = `
					import { defineProps } from '@vue/runtime-core';

					${regularScriptBlockContent}

					const Props = ${defineProps[0]}

					export default function ${className}__AstroComponent_${propsGenericType}(_props: typeof Props): any {
						<div></div>
					}
				`;
				}
			}
		}
	} catch (e: any) {
		return result;
	}

	return result;
}