From 478968b6f24a970a7876f3cd03cd65776e61409e Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Wed, 31 Jul 2024 18:47:56 +0100 Subject: [PATCH] feat(cli-utils): Add separate support packages for Vue & Svelte (#361) --- .changeset/beige-fishes-lay.md | 5 ++ packages/cli-utils/LICENSE.md | 24 ------ packages/cli-utils/package.json | 17 ++-- .../src/commands/doctor/helpers/versions.ts | 28 +++++++ .../cli-utils/src/commands/doctor/runner.ts | 50 ++++++++++++ .../cli-utils/src/commands/shared/logger.ts | 5 +- packages/cli-utils/src/ts/transformers.ts | 75 +++++++++++++++++ .../cli-utils/src/ts/transformers/index.ts | 40 ---------- packages/cli-utils/src/utils/error.ts | 18 +++++ packages/svelte-support/LICENSE.md | 21 +++++ packages/svelte-support/package.json | 57 +++++++++++++ .../svelte.ts => svelte-support/src/index.ts} | 3 +- packages/svelte-support/src/types.ts | 80 +++++++++++++++++++ packages/vue-support/LICENSE.md | 21 +++++ packages/vue-support/package.json | 53 ++++++++++++ .../vue.ts => vue-support/src/index.ts} | 3 +- packages/vue-support/src/types.ts | 80 +++++++++++++++++++ pnpm-lock.yaml | 60 +++++++++----- website/get-started/installation.md | 57 ++++++++++++- 19 files changed, 604 insertions(+), 93 deletions(-) create mode 100644 .changeset/beige-fishes-lay.md create mode 100644 packages/cli-utils/src/ts/transformers.ts delete mode 100644 packages/cli-utils/src/ts/transformers/index.ts create mode 100644 packages/cli-utils/src/utils/error.ts create mode 100644 packages/svelte-support/LICENSE.md create mode 100644 packages/svelte-support/package.json rename packages/{cli-utils/src/ts/transformers/svelte.ts => svelte-support/src/index.ts} (97%) create mode 100644 packages/svelte-support/src/types.ts create mode 100644 packages/vue-support/LICENSE.md create mode 100644 packages/vue-support/package.json rename packages/{cli-utils/src/ts/transformers/vue.ts => vue-support/src/index.ts} (98%) create mode 100644 packages/vue-support/src/types.ts diff --git a/.changeset/beige-fishes-lay.md b/.changeset/beige-fishes-lay.md new file mode 100644 index 00000000..f64751c6 --- /dev/null +++ b/.changeset/beige-fishes-lay.md @@ -0,0 +1,5 @@ +--- +"@gql.tada/cli-utils": minor +--- + +Split `.vue` and `.svelte` SFC file support out into support packages. If you need Vue support, you must now install `@gql.tada/vue-support` alongside `gql.tada`, and if you need Svelte support, you must now install `@gql.tada/svelte-support` alongside `gql.tada`. diff --git a/packages/cli-utils/LICENSE.md b/packages/cli-utils/LICENSE.md index 268a2bfc..9f28d59d 100644 --- a/packages/cli-utils/LICENSE.md +++ b/packages/cli-utils/LICENSE.md @@ -74,30 +74,6 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -## @jridgewell/sourcemap-codec - -The MIT License - -Copyright (c) 2015 Rich Harris - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ## @volar/source-map MIT License diff --git a/packages/cli-utils/package.json b/packages/cli-utils/package.json index a49a7078..25acfb43 100644 --- a/packages/cli-utils/package.json +++ b/packages/cli-utils/package.json @@ -41,7 +41,6 @@ }, "devDependencies": { "@clack/prompts": "^0.7.0", - "@jridgewell/sourcemap-codec": "^1.4.15", "@types/node": "^20.11.0", "@volar/source-map": "^2.1.6", "clipanion": "4.0.0-rc.3", @@ -52,19 +51,25 @@ "typanion": "^3.14.0", "type-fest": "^4.10.2", "typescript": "^5.5.2", - "vscode-languageserver-textdocument": "^1.0.11", "wonka": "^6.3.4" }, "dependencies": { "@0no-co/graphqlsp": "^1.12.9", "@gql.tada/internal": "workspace:*", - "@vue/compiler-dom": "^3.4.23", - "@vue/language-core": "~2.0.0", - "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0", - "svelte2tsx": "^0.7.6" + "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@gql.tada/svelte-support": { + "optional": true + }, + "@gql.tada/vue-support": { + "optional": true + } }, "peerDependencies": { "@0no-co/graphqlsp": "^1.12.9", + "@gql.tada/svelte-support": "workspace:*", + "@gql.tada/vue-support": "workspace:*", "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0", "typescript": "^5.0.0" }, diff --git a/packages/cli-utils/src/commands/doctor/helpers/versions.ts b/packages/cli-utils/src/commands/doctor/helpers/versions.ts index d398b017..69bf8947 100644 --- a/packages/cli-utils/src/commands/doctor/helpers/versions.ts +++ b/packages/cli-utils/src/commands/doctor/helpers/versions.ts @@ -57,3 +57,31 @@ export const getGqlTadaVersion = async (meta: PackageJson): Promise => { + const pkg = '@gql.tada/svelte-support'; + const isInstalled = !!meta.devDependencies?.[pkg] || !!meta.devDependencies?.[pkg]; + if (isInstalled) { + return true; + } + try { + // NOTE: Resolved from current folder, since it's a child dependency + return !!createRequire(__dirname)(`${pkg}/package.json`)?.version; + } catch (_error) { + return false; + } +}; + +export const hasVueSupport = async (meta: PackageJson): Promise => { + const pkg = '@gql.tada/vue-support'; + const isInstalled = !!meta.devDependencies?.[pkg] || !!meta.devDependencies?.[pkg]; + if (isInstalled) { + return true; + } + try { + // NOTE: Resolved from current folder, since it's a child dependency + return !!createRequire(__dirname)(`${pkg}/package.json`)?.version; + } catch (_error) { + return false; + } +}; diff --git a/packages/cli-utils/src/commands/doctor/runner.ts b/packages/cli-utils/src/commands/doctor/runner.ts index a8bcba8a..60663cf1 100644 --- a/packages/cli-utils/src/commands/doctor/runner.ts +++ b/packages/cli-utils/src/commands/doctor/runner.ts @@ -1,3 +1,4 @@ +import type ts from 'typescript'; import path from 'node:path'; import type { GraphQLSPConfig, LoadConfigResult } from '@gql.tada/internal'; @@ -5,6 +6,7 @@ import { loadRef, loadConfig, parseConfig } from '@gql.tada/internal'; import type { ComposeInput } from '../../term'; import { MINIMUM_VERSIONS, semverComply } from '../../utils/semver'; +import { programFactory } from '../../ts'; import { findGraphQLConfig } from './helpers/graphqlConfig'; import * as versions from './helpers/versions'; import * as vscode from './helpers/vscode'; @@ -28,6 +30,7 @@ const enum Messages { CHECK_TS_VERSION = 'Checking TypeScript version', CHECK_DEPENDENCIES = 'Checking installed dependencies', CHECK_TSCONFIG = 'Checking tsconfig.json', + CHECK_EXTERNAL_FILES = 'Checking external files support', CHECK_VSCODE = 'Checking VSCode setup', CHECK_SCHEMA = 'Checking schema', } @@ -145,6 +148,8 @@ export async function* run(): AsyncIterable { yield logger.completedTask(Messages.CHECK_TSCONFIG); + yield* runExternalFilesChecks(configResult, packageJson); + yield* runVSCodeChecks(); yield logger.runningTask(Messages.CHECK_SCHEMA); @@ -216,3 +221,48 @@ async function* runVSCodeChecks(): AsyncIterable { } } } + +async function* runExternalFilesChecks( + configResult: LoadConfigResult, + packageJson: versions.PackageJson +): AsyncIterable { + let externalFiles: readonly ts.SourceFile[] = []; + try { + const factory = programFactory(configResult); + externalFiles = factory.createExternalFiles(); + } catch (_error) { + // NOTE: If the project fails to load, we currently just ignore this check and move on + return; + } + + if (externalFiles.length) { + yield logger.runningTask(Messages.CHECK_EXTERNAL_FILES); + await delay(); + + const extensions = new Set( + externalFiles.map((sourceFile) => path.extname(sourceFile.fileName)) + ); + + if (extensions.has('.svelte') && !(await versions.hasSvelteSupport(packageJson))) { + yield logger.failedTask(Messages.CHECK_EXTERNAL_FILES); + throw logger.errorMessage( + `A version of ${logger.code( + '@gql.tada/svelte-support' + )} must be installed for Svelte file support.\n` + + logger.hint(`Have you installed ${logger.code('@gql.tada/svelte-support')}?`) + ); + } + + if (extensions.has('.vue') && !(await versions.hasVueSupport(packageJson))) { + yield logger.failedTask(Messages.CHECK_EXTERNAL_FILES); + throw logger.errorMessage( + `A version of ${logger.code( + '@gql.tada/vue-support' + )} must be installed for Vue file support.\n` + + logger.hint(`Have you installed ${logger.code('@gql.tada/vue-support')}?`) + ); + } + + yield logger.completedTask(Messages.CHECK_EXTERNAL_FILES); + } +} diff --git a/packages/cli-utils/src/commands/shared/logger.ts b/packages/cli-utils/src/commands/shared/logger.ts index e77af687..f80a7afd 100644 --- a/packages/cli-utils/src/commands/shared/logger.ts +++ b/packages/cli-utils/src/commands/shared/logger.ts @@ -53,7 +53,10 @@ export function externalError(message: string, error: unknown) { (error.name === 'TSError' || error.name === 'TadaError' || 'code' in error) ) { title = 'code' in error ? 'System Error' : 'Error'; - text = (error as Error).message.trim(); + text = + error.name === 'TadaError' + ? t.text([t.cmd(t.CSI.Style, t.Style.Blue), (error as Error).message]) + : (error as Error).message.trim(); } else if ('stack' in error && typeof error.stack === 'string') { title = 'Unexpected Error'; text = `${error.stack}`; diff --git a/packages/cli-utils/src/ts/transformers.ts b/packages/cli-utils/src/ts/transformers.ts new file mode 100644 index 00000000..464382a9 --- /dev/null +++ b/packages/cli-utils/src/ts/transformers.ts @@ -0,0 +1,75 @@ +import type ts from 'typescript'; +import * as path from 'node:path'; + +import { TadaError, TadaErrorCode } from '../utils/error'; + +let _svelte: typeof import('@gql.tada/svelte-support'); +let _vue: typeof import('@gql.tada/vue-support'); + +const transformSvelte = async ( + ...args: Parameters +): Promise> => { + if (!_svelte) { + try { + _svelte = await import('@gql.tada/svelte-support'); + } catch (_error) { + throw new TadaError( + TadaErrorCode.SVELTE_SUPPORT, + 'For Svelte support the `@gql.tada/svelte-support` package must be installed.\n' + + 'Install the package and try again.' + ); + } + } + return _svelte.transform(...args); +}; + +const transformVue = async ( + ...args: Parameters +): Promise> => { + if (!_vue) { + try { + _vue = await import('@gql.tada/vue-support'); + } catch (_error) { + throw new TadaError( + TadaErrorCode.VUE_SUPPORT, + 'For Vue support the `@gql.tada/vue-support` package must be installed.\n' + + 'Install the package and try again.' + ); + } + } + return _vue.transform(...args); +}; + +const checkVue = async (): Promise => { + if (!_vue) { + try { + _vue = await import('@gql.tada/vue-support'); + } catch (_error) { + throw new TadaError( + TadaErrorCode.VUE_SUPPORT, + 'For Vue support the `@gql.tada/vue-support` package must be installed.\n' + + 'Install the package and try again.' + ); + } + } + return _vue.check(); +}; + +export const transformExtensions = ['.svelte', '.vue'] as const; + +export const transform = async (sourceFile: ts.SourceFile) => { + const extname = path.extname(sourceFile.fileName); + if (extname === '.svelte') { + return transformSvelte(sourceFile); + } else if (extname === '.vue') { + await checkVue(); + return transformVue(sourceFile); + } else { + throw new TadaError( + TadaErrorCode.UNKNOWN_EXTERNAL_FILE, + `Tried transforming unknown file type "${extname}". Supported: ${transformExtensions.join( + ', ' + )}` + ); + } +}; diff --git a/packages/cli-utils/src/ts/transformers/index.ts b/packages/cli-utils/src/ts/transformers/index.ts deleted file mode 100644 index 926164e0..00000000 --- a/packages/cli-utils/src/ts/transformers/index.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type ts from 'typescript'; -import * as path from 'node:path'; -import type { VirtualCode } from '@vue/language-core'; - -let _svelte: typeof import('./svelte'); -let _vue: typeof import('./vue'); - -const transformSvelte = async ( - ...args: Parameters -): Promise> => { - return (_svelte || (_svelte = await import('./svelte'))).transform(...args); -}; - -const transformVue = async ( - ...args: Parameters -): Promise> => { - return (_vue || (_vue = await import('./vue'))).transform(...args); -}; - -const checkVue = async (): Promise => { - return (_vue || (_vue = await import('./vue'))).check(); -}; - -export const transformExtensions = ['.svelte', '.vue'] as const; - -export const transform = async (sourceFile: ts.SourceFile): Promise => { - const extname = path.extname(sourceFile.fileName); - if (extname === '.svelte') { - return transformSvelte(sourceFile); - } else if (extname === '.vue') { - await checkVue(); - return transformVue(sourceFile); - } else { - throw new Error( - `Tried transforming unknown file type "${extname}". Supported: ${transformExtensions.join( - ', ' - )}` - ); - } -}; diff --git a/packages/cli-utils/src/utils/error.ts b/packages/cli-utils/src/utils/error.ts new file mode 100644 index 00000000..edc38c7e --- /dev/null +++ b/packages/cli-utils/src/utils/error.ts @@ -0,0 +1,18 @@ +export const enum TadaErrorCode { + VUE_SUPPORT, + SVELTE_SUPPORT, + UNKNOWN_EXTERNAL_FILE, +} + +export class TadaError extends Error { + static isTadaError(error: unknown): error is TadaError { + return !!(typeof error === 'object' && error && 'name' in error && error.name === 'TadaError'); + } + + readonly code: TadaErrorCode; + constructor(code: TadaErrorCode, message: string) { + super(message); + this.code = code; + this.name = 'TadaError'; + } +} diff --git a/packages/svelte-support/LICENSE.md b/packages/svelte-support/LICENSE.md new file mode 100644 index 00000000..adef8fd1 --- /dev/null +++ b/packages/svelte-support/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 0no.co + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/packages/svelte-support/package.json b/packages/svelte-support/package.json new file mode 100644 index 00000000..ae0c35c5 --- /dev/null +++ b/packages/svelte-support/package.json @@ -0,0 +1,57 @@ +{ + "name": "@gql.tada/svelte-support", + "version": "1.0.0", + "public": true, + "description": "Svelte Support package for gql.tada’s CLI tool.", + "author": "0no.co ", + "sideEffects": false, + "source": "./src/index.ts", + "main": "./dist/gql-tada-svelte-support", + "module": "./dist/gql-tada-svelte-support.mjs", + "types": "./dist/gql-tada-svelte-support.d.ts", + "exports": { + ".": { + "types": "./dist/gql-tada-svelte-support.d.ts", + "import": "./dist/gql-tada-svelte-support.mjs", + "require": "./dist/gql-tada-svelte-support.js", + "source": "./src/index.ts" + }, + "./package.json": "./package.json" + }, + "files": [ + "CHANGELOG.md", + "LICENSE.md", + "README.md", + "dist/" + ], + "repository": { + "type": "git", + "url": "https://github.com/0no-co/gql.tada.git", + "directory": "packages/svelte-support" + }, + "bugs": { + "url": "https://github.com/0no-co/gql.tada/issues" + }, + "homepage": "https://gql-tada.0no.co/", + "license": "MIT", + "scripts": { + "build": "rollup -c ../../scripts/rollup.config.mjs", + "clean": "rimraf dist node_modules/.cache", + "prepublishOnly": "run-s clean build" + }, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15", + "svelte2tsx": "^0.7.6", + "vscode-languageserver-textdocument": "^1.0.11" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "publishConfig": { + "access": "public", + "provenance": true + }, + "devDependencies": { + "@vue/language-core": "~2.0.0" + } +} diff --git a/packages/cli-utils/src/ts/transformers/svelte.ts b/packages/svelte-support/src/index.ts similarity index 97% rename from packages/cli-utils/src/ts/transformers/svelte.ts rename to packages/svelte-support/src/index.ts index 1dbba66e..bb7ccbec 100644 --- a/packages/cli-utils/src/ts/transformers/svelte.ts +++ b/packages/svelte-support/src/index.ts @@ -1,9 +1,10 @@ import ts from 'typescript'; -import type { CodeMapping, VirtualCode } from '@vue/language-core'; import { decode } from '@jridgewell/sourcemap-codec'; import { svelte2tsx } from 'svelte2tsx'; import { TextDocument } from 'vscode-languageserver-textdocument'; +import type { CodeMapping, VirtualCode } from './types'; + // See: https://github.com/johnsoncodehk/language-tools/blob/volar2/packages/language-server/src/languagePlugin.ts export const transform = (sourceFile: ts.SourceFile): VirtualCode | undefined => { const text = sourceFile.getFullText(); diff --git a/packages/svelte-support/src/types.ts b/packages/svelte-support/src/types.ts new file mode 100644 index 00000000..91b7f41a --- /dev/null +++ b/packages/svelte-support/src/types.ts @@ -0,0 +1,80 @@ +export interface TextSpan { + start: number; + length: number; +} + +export interface TextChangeRange { + span: TextSpan; + newLength: number; +} + +export interface IScriptSnapshot { + /** Gets a portion of the script snapshot specified by [start, end). */ + getText(start: number, end: number): string; + /** Gets the length of this script snapshot. */ + getLength(): number; + /** + * Gets the TextChangeRange that describe how the text changed between this text and + * an older version. This information is used by the incremental parser to determine + * what sections of the script need to be re-parsed. 'undefined' can be returned if the + * change range cannot be determined. However, in that case, incremental parsing will + * not happen and the entire document will be re - parsed. + */ + getChangeRange(oldSnapshot: IScriptSnapshot): TextChangeRange | undefined; + /** Releases all resources held by this script snapshot */ + dispose?(): void; +} + +export interface CodeInformation { + /** virtual code is expected to support verification */ + verification?: + | boolean + | { + shouldReport?(): boolean; + }; + /** virtual code is expected to support assisted completion */ + completion?: + | boolean + | { + isAdditional?: boolean; + onlyImport?: boolean; + }; + /** virtual code is expected correctly reflect semantic of the source code */ + semantic?: + | boolean + | { + shouldHighlight?(): boolean; + }; + /** virtual code is expected correctly reflect reference relationships of the source code */ + navigation?: + | boolean + | { + shouldRename?(): boolean; + resolveRenameNewName?(newName: string): string; + resolveRenameEditText?(newText: string): string; + }; + /** virtual code is expected correctly reflect the structural information of the source code */ + structure?: boolean; + /** virtual code is expected correctly reflect the format information of the source code */ + format?: boolean; +} + +export interface Mapping { + sourceOffsets: number[]; + generatedOffsets: number[]; + lengths: number[]; + generatedLengths?: number[]; + data: Data; +} + +export type CodeMapping = Mapping; + +export interface VirtualCode { + id: string; + languageId: string; + snapshot: IScriptSnapshot; + mappings: CodeMapping[]; + associatedScriptMappings?: Map; + embeddedCodes?: VirtualCode[]; + linkedCodeMappings?: Mapping[]; +} diff --git a/packages/vue-support/LICENSE.md b/packages/vue-support/LICENSE.md new file mode 100644 index 00000000..adef8fd1 --- /dev/null +++ b/packages/vue-support/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 0no.co + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/packages/vue-support/package.json b/packages/vue-support/package.json new file mode 100644 index 00000000..9104e7b6 --- /dev/null +++ b/packages/vue-support/package.json @@ -0,0 +1,53 @@ +{ + "name": "@gql.tada/vue-support", + "version": "1.0.0", + "public": true, + "description": "Vue Support package for gql.tada’s CLI tool.", + "author": "0no.co ", + "sideEffects": false, + "source": "./src/index.ts", + "main": "./dist/gql-tada-vue-support", + "module": "./dist/gql-tada-vue-support.mjs", + "types": "./dist/gql-tada-vue-support.d.ts", + "exports": { + ".": { + "types": "./dist/gql-tada-vue-support.d.ts", + "import": "./dist/gql-tada-vue-support.mjs", + "require": "./dist/gql-tada-vue-support.js", + "source": "./src/index.ts" + }, + "./package.json": "./package.json" + }, + "files": [ + "CHANGELOG.md", + "LICENSE.md", + "README.md", + "dist/" + ], + "repository": { + "type": "git", + "url": "https://github.com/0no-co/gql.tada.git", + "directory": "packages/vue-support" + }, + "bugs": { + "url": "https://github.com/0no-co/gql.tada/issues" + }, + "homepage": "https://gql-tada.0no.co/", + "license": "MIT", + "scripts": { + "build": "rollup -c ../../scripts/rollup.config.mjs", + "clean": "rimraf dist node_modules/.cache", + "prepublishOnly": "run-s clean build" + }, + "dependencies": { + "@vue/compiler-dom": "^3.4.23", + "@vue/language-core": "~2.0.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "publishConfig": { + "access": "public", + "provenance": true + } +} diff --git a/packages/cli-utils/src/ts/transformers/vue.ts b/packages/vue-support/src/index.ts similarity index 98% rename from packages/cli-utils/src/ts/transformers/vue.ts rename to packages/vue-support/src/index.ts index a9918045..cf22afeb 100644 --- a/packages/cli-utils/src/ts/transformers/vue.ts +++ b/packages/vue-support/src/index.ts @@ -1,9 +1,10 @@ import ts from 'typescript'; -import type { VirtualCode } from '@vue/language-core'; import * as vueCompilerDOM from '@vue/compiler-dom'; import * as vue from '@vue/language-core'; import { parse } from '@vue/language-core'; +import type { VirtualCode } from './types'; + const useVueFilePlugin = (): vue.VueLanguagePluginReturn => { return { version: 2, diff --git a/packages/vue-support/src/types.ts b/packages/vue-support/src/types.ts new file mode 100644 index 00000000..91b7f41a --- /dev/null +++ b/packages/vue-support/src/types.ts @@ -0,0 +1,80 @@ +export interface TextSpan { + start: number; + length: number; +} + +export interface TextChangeRange { + span: TextSpan; + newLength: number; +} + +export interface IScriptSnapshot { + /** Gets a portion of the script snapshot specified by [start, end). */ + getText(start: number, end: number): string; + /** Gets the length of this script snapshot. */ + getLength(): number; + /** + * Gets the TextChangeRange that describe how the text changed between this text and + * an older version. This information is used by the incremental parser to determine + * what sections of the script need to be re-parsed. 'undefined' can be returned if the + * change range cannot be determined. However, in that case, incremental parsing will + * not happen and the entire document will be re - parsed. + */ + getChangeRange(oldSnapshot: IScriptSnapshot): TextChangeRange | undefined; + /** Releases all resources held by this script snapshot */ + dispose?(): void; +} + +export interface CodeInformation { + /** virtual code is expected to support verification */ + verification?: + | boolean + | { + shouldReport?(): boolean; + }; + /** virtual code is expected to support assisted completion */ + completion?: + | boolean + | { + isAdditional?: boolean; + onlyImport?: boolean; + }; + /** virtual code is expected correctly reflect semantic of the source code */ + semantic?: + | boolean + | { + shouldHighlight?(): boolean; + }; + /** virtual code is expected correctly reflect reference relationships of the source code */ + navigation?: + | boolean + | { + shouldRename?(): boolean; + resolveRenameNewName?(newName: string): string; + resolveRenameEditText?(newText: string): string; + }; + /** virtual code is expected correctly reflect the structural information of the source code */ + structure?: boolean; + /** virtual code is expected correctly reflect the format information of the source code */ + format?: boolean; +} + +export interface Mapping { + sourceOffsets: number[]; + generatedOffsets: number[]; + lengths: number[]; + generatedLengths?: number[]; + data: Data; +} + +export type CodeMapping = Mapping; + +export interface VirtualCode { + id: string; + languageId: string; + snapshot: IScriptSnapshot; + mappings: CodeMapping[]; + associatedScriptMappings?: Map; + embeddedCodes?: VirtualCode[]; + linkedCodeMappings?: Mapping[]; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4f615749..6496cac9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -229,25 +229,19 @@ importers: '@gql.tada/internal': specifier: workspace:* version: link:../internal - '@vue/compiler-dom': - specifier: ^3.4.23 - version: 3.4.25 - '@vue/language-core': - specifier: ~2.0.0 - version: 2.0.29(typescript@5.5.2) + '@gql.tada/svelte-support': + specifier: workspace:* + version: link:../svelte-support + '@gql.tada/vue-support': + specifier: workspace:* + version: link:../vue-support graphql: specifier: ^15.5.0 || ^16.0.0 || ^17.0.0 version: 16.8.1 - svelte2tsx: - specifier: ^0.7.6 - version: 0.7.6(svelte@4.2.17)(typescript@5.5.2) devDependencies: '@clack/prompts': specifier: ^0.7.0 version: 0.7.0 - '@jridgewell/sourcemap-codec': - specifier: ^1.4.15 - version: 1.4.15 '@types/node': specifier: ^20.11.0 version: 20.11.0 @@ -278,9 +272,6 @@ importers: typescript: specifier: ^5.5.2 version: 5.5.2 - vscode-languageserver-textdocument: - specifier: ^1.0.11 - version: 1.0.11 wonka: specifier: ^6.3.4 version: 6.3.4 @@ -316,6 +307,37 @@ importers: specifier: ^5.5.2 version: 5.5.2 + packages/svelte-support: + dependencies: + '@jridgewell/sourcemap-codec': + specifier: ^1.4.15 + version: 1.5.0 + svelte2tsx: + specifier: ^0.7.6 + version: 0.7.6(svelte@4.2.17)(typescript@5.5.2) + typescript: + specifier: ^5.5.2 + version: 5.5.2 + vscode-languageserver-textdocument: + specifier: ^1.0.11 + version: 1.0.11 + devDependencies: + '@vue/language-core': + specifier: ~2.0.0 + version: 2.0.29(typescript@5.5.2) + + packages/vue-support: + dependencies: + '@vue/compiler-dom': + specifier: ^3.4.23 + version: 3.4.25 + '@vue/language-core': + specifier: ~2.0.0 + version: 2.0.29(typescript@5.5.2) + typescript: + specifier: ^5.5.2 + version: 5.5.2 + website: dependencies: '@apollo/client': @@ -4755,7 +4777,7 @@ snapshots: '@jridgewell/gen-mapping@0.3.5': dependencies: '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping': 0.3.25 '@jridgewell/resolve-uri@3.1.2': {} @@ -4780,7 +4802,7 @@ snapshots: '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 '@manypkg/find-root@1.1.0': dependencies: @@ -5705,7 +5727,7 @@ snapshots: code-red@1.0.4: dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 '@types/estree': 1.0.5 acorn: 8.11.3 estree-walker: 3.0.3 @@ -6610,7 +6632,7 @@ snapshots: magic-string@0.30.10: dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 magic-string@0.30.11: dependencies: diff --git a/website/get-started/installation.md b/website/get-started/installation.md index 9a507de8..b52c677f 100644 --- a/website/get-started/installation.md +++ b/website/get-started/installation.md @@ -12,7 +12,7 @@ repository.](https://github.com/0no-co/gql.tada/blob/main/examples/example-pokem With `gql.tada`, you'll mainly interact with three different parts of the library: - the library code you import from the `gql.tada` package - the TypeScript plugin, `gql.tada/ts-plugin` -- and the `gql.tada` CLI +- and [the `gql.tada` CLI](/get-started/workflows) ## Step 1 — Installing packages @@ -340,6 +340,8 @@ to use it. ``` ::: +--- + ### VSCode Setup As shown above, `gql.tada` has a TypeScript plugin to provide @@ -365,3 +367,56 @@ To resolve this, you should create a `.vscode/settings.json` file to prompt you To enable syntax highlighting for GraphQL, you can install the official [“GraphQL: Syntax Highlighting” VSCode extension.](https://marketplace.visualstudio.com/items?itemName=GraphQL.vscode-graphql-syntax) + +--- + +### Vue and Svelte Support + +If you're using Vue's `.vue` files and Svelte's `.svelte` files, the +TypeScript plugin won't be able to run in your editor under normal +circumstances. +While some implementations exist for TypeScript to run and type +check Vue and Svelte files, `gql.tada` won't have any output in +these cases. + +However, while the TypeScript plugin may not support `.vue` and +`.svelte` files, [the `gql.tada check` command does.](/get-started/workflows#running-diagnostics) +To enable support for either files, you'll need to install the +corresponding support packages. + +::: code-group +```sh [npm] +# for Vue +npm install -D @gql.tada/vue-support +# for Svelte +npm install -D @gql.tada/svelte-support +``` + +```sh [pnpm] +# for Vue +pnpm add -D @gql.tada/vue-support +# for Svelte +pnpm add -D @gql.tada/svelte-support +``` + +```sh [yarn] +# for Vue +yarn add -D @gql.tada/vue-support +# for Svelte +yarn add -D @gql.tada/svelte-support +``` + +```sh [bun] +# for Vue +bun add -d @gql.tada/vue-support +# for Svelte +bun add -d @gql.tada/svelte-support +``` +::: + +Once these are installed, the CLI's `check` and other commands will +be able to parse and check external files for `gql.tada` errors. + + + Learn more about using the CLI +