From f9ed77bb0d71d1644d524547a24963210f4ecaff Mon Sep 17 00:00:00 2001 From: Erika <3019731+Princesseuh@users.noreply.github.com> Date: Fri, 8 Jul 2022 17:47:01 -0400 Subject: [PATCH] Add editor integrations to language integrations (#3864) --- .changeset/nasty-students-run.md | 6 +++ package.json | 9 ++++ packages/integrations/svelte/package.json | 6 ++- packages/integrations/svelte/src/editor.cts | 23 +++++++++ packages/integrations/vue/package.json | 5 +- packages/integrations/vue/src/editor.cts | 55 +++++++++++++++++++++ pnpm-lock.yaml | 21 ++++++++ scripts/cmd/build.js | 12 ++++- 8 files changed, 131 insertions(+), 6 deletions(-) create mode 100644 .changeset/nasty-students-run.md create mode 100644 packages/integrations/svelte/src/editor.cts create mode 100644 packages/integrations/vue/src/editor.cts diff --git a/.changeset/nasty-students-run.md b/.changeset/nasty-students-run.md new file mode 100644 index 000000000000..e83afd915a43 --- /dev/null +++ b/.changeset/nasty-students-run.md @@ -0,0 +1,6 @@ +--- +'@astrojs/svelte': patch +'@astrojs/vue': patch +--- + +Add entrypoints for editor support for Vue and Svelte (destined to be used by our language server) diff --git a/package.json b/package.json index ee49bddefab6..06c40e400d68 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,15 @@ }, "packageManager": "pnpm@7.5.0", "pnpm": { + "packageExtensions": { + "svelte2tsx": { + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + } + }, "peerDependencyRules": { "ignoreMissing": [ "rollup", diff --git a/packages/integrations/svelte/package.json b/packages/integrations/svelte/package.json index 755fbc8d3807..fe0e6976b3f5 100644 --- a/packages/integrations/svelte/package.json +++ b/packages/integrations/svelte/package.json @@ -21,20 +21,22 @@ "homepage": "https://astro.build", "exports": { ".": "./dist/index.js", + "./editor": "./dist/editor.cjs", "./*": "./*", "./client.js": "./client.js", "./server.js": "./server.js", "./package.json": "./package.json" }, "scripts": { - "build": "astro-scripts build \"src/**/*.ts\" && tsc", - "build:ci": "astro-scripts build \"src/**/*.ts\"", + "build": "astro-scripts build \"src/index.ts\" && astro-scripts build \"src/editor.cts\" --force-cjs --no-clean-dist && tsc", + "build:ci": "astro-scripts build \"src/**/*.ts\" && astro-scripts build \"src/editor.cts\" --force-cjs --no-clean-dist", "dev": "astro-scripts dev \"src/**/*.ts\"" }, "dependencies": { "@sveltejs/vite-plugin-svelte": "^1.0.0-next.48", "postcss-load-config": "^3.1.4", "svelte-preprocess": "^4.10.7", + "svelte2tsx": "^0.5.11", "vite": "^2.9.10" }, "devDependencies": { diff --git a/packages/integrations/svelte/src/editor.cts b/packages/integrations/svelte/src/editor.cts new file mode 100644 index 000000000000..202609d3393f --- /dev/null +++ b/packages/integrations/svelte/src/editor.cts @@ -0,0 +1,23 @@ +import { svelte2tsx } from 'svelte2tsx'; + +export function toTSX(code: string, className: string): string { + let result = ` + let ${className}__AstroComponent_: Error + export default ${className}__AstroComponent_ + `; + + try { + let tsx = svelte2tsx(code).code; + tsx = 'let Props = render().props;\n' + tsx; + + // Replace Svelte's class export with a function export + result = tsx.replace( + /^export default[\S\s]*/gm, + `export default function ${className}__AstroComponent_(_props: typeof Props): any {}` + ); + } catch (e: any) { + return result; + } + + return result; +} diff --git a/packages/integrations/vue/package.json b/packages/integrations/vue/package.json index 03d7b7b2fe1e..07ed5caba3ff 100644 --- a/packages/integrations/vue/package.json +++ b/packages/integrations/vue/package.json @@ -21,14 +21,15 @@ "homepage": "https://astro.build", "exports": { ".": "./dist/index.js", + "./editor": "./dist/editor.cjs", "./*": "./*", "./client.js": "./client.js", "./server.js": "./server.js", "./package.json": "./package.json" }, "scripts": { - "build": "astro-scripts build \"src/**/*.ts\" && tsc", - "build:ci": "astro-scripts build \"src/**/*.ts\"", + "build": "astro-scripts build \"src/index.ts\" && astro-scripts build \"src/editor.cts\" --force-cjs --no-clean-dist && tsc", + "build:ci": "astro-scripts build \"src/**/*.ts\" && astro-scripts build \"src/editor.cts\" --force-cjs --no-clean-dist", "dev": "astro-scripts dev \"src/**/*.ts\"" }, "dependencies": { diff --git a/packages/integrations/vue/src/editor.cts b/packages/integrations/vue/src/editor.cts new file mode 100644 index 000000000000..29adaa09cad6 --- /dev/null +++ b/packages/integrations/vue/src/editor.cts @@ -0,0 +1,55 @@ +import { parse } from '@vue/compiler-sfc'; + +export function toTSX(code: string, className: string): string { + let result = `export default function ${className}__AstroComponent_(_props: Record): 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 knowledgable 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_ + `; + } + + if (parsedResult.descriptor.scriptSetup) { + const definePropsType = + parsedResult.descriptor.scriptSetup.content.match(/defineProps<([\s\S]+)>/m); + + if (definePropsType) { + result = ` + ${parsedResult.descriptor.scriptSetup.content} + + export default function ${className}__AstroComponent_(_props: ${definePropsType[1]}): any { +
+ } + `; + } else { + const defineProps = + parsedResult.descriptor.scriptSetup.content.match(/defineProps\([\s\S]+\)/m); + + if (defineProps) { + result = ` + import { defineProps } from '@vue/runtime-core'; + + const Props = ${defineProps[0]} + + export default function ${className}__AstroComponent_(_props: typeof Props): any { +
+ } + `; + } + } + } + } catch (e: any) { + return result; + } + + return result; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d62ab659bc20..81b1e074a65b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,5 +1,7 @@ lockfileVersion: 5.4 +packageExtensionsChecksum: 01871422d489547c532184effb134b35 + patchedDependencies: '@changesets/cli@2.23.0': hash: kcozqtpxuwjzskw6zg5royevn4 @@ -2184,11 +2186,13 @@ importers: postcss-load-config: ^3.1.4 svelte: ^3.48.0 svelte-preprocess: ^4.10.7 + svelte2tsx: ^0.5.11 vite: ^2.9.10 dependencies: '@sveltejs/vite-plugin-svelte': 1.0.0-next.49_svelte@3.49.0+vite@2.9.14 postcss-load-config: 3.1.4 svelte-preprocess: 4.10.7_k3vaqsyrx2lfvza3vdeafxime4 + svelte2tsx: 0.5.11_svelte@3.49.0 vite: 2.9.14 devDependencies: astro: link:../../astro @@ -14277,11 +14281,28 @@ packages: resolution: {integrity: sha512-+lmjic1pApJWDfPCpUUTc1m8azDqYCG1JN9YEngrx/hUyIcFJo6VZhj0A1Ai0wqoHcEIuQy+e9tk+4uDgdtsFA==} engines: {node: '>= 8'} + /svelte2tsx/0.5.11_svelte@3.49.0: + resolution: {integrity: sha512-Is95G1wqNvEUJZ9DITRS2zfMwVJRZztMduPs1vJJ0cm65WUg/avBl5vBXjHycQL/qmFpaqa3NG4qWnf7bCHPag==} + peerDependencies: + svelte: ^3.24 + typescript: ^4.1.2 + peerDependenciesMeta: + typescript: + optional: true + dependencies: + dedent-js: 1.0.1 + pascal-case: 3.1.2 + svelte: 3.49.0 + dev: false + /svelte2tsx/0.5.11_ueozcsexptisi2awlbuwt6eqmq: resolution: {integrity: sha512-Is95G1wqNvEUJZ9DITRS2zfMwVJRZztMduPs1vJJ0cm65WUg/avBl5vBXjHycQL/qmFpaqa3NG4qWnf7bCHPag==} peerDependencies: svelte: ^3.24 typescript: ^4.1.2 + peerDependenciesMeta: + typescript: + optional: true dependencies: dedent-js: 1.0.1 pascal-case: 3.1.2 diff --git a/scripts/cmd/build.js b/scripts/cmd/build.js index 764b26eeda3d..5d59f5180127 100644 --- a/scripts/cmd/build.js +++ b/scripts/cmd/build.js @@ -47,6 +47,9 @@ export default async function build(...args) { )) ); + const noClean = args.includes('--no-clean-dist'); + const forceCJS = args.includes('--force-cjs'); + const { type = 'module', version, @@ -54,9 +57,13 @@ export default async function build(...args) { } = await fs.readFile('./package.json').then((res) => JSON.parse(res.toString())); // expose PACKAGE_VERSION on process.env for CLI utils config.define = { 'process.env.PACKAGE_VERSION': JSON.stringify(version) }; - const format = type === 'module' ? 'esm' : 'cjs'; + const format = type === 'module' && !forceCJS ? 'esm' : 'cjs'; + const outdir = 'dist'; - await clean(outdir); + + if (!noClean) { + await clean(outdir); + } if (!isDev) { await esbuild.build({ @@ -64,6 +71,7 @@ export default async function build(...args) { bundle: false, entryPoints, outdir, + outExtension: forceCJS ? { '.js': '.cjs' } : {}, format, }); return;