From d15939cfe168868ebaf188342b914b29588709c0 Mon Sep 17 00:00:00 2001 From: halfnelson Date: Sun, 26 Jul 2020 02:07:09 +1000 Subject: [PATCH] Toggle JSX namespace based on svelte vs svelte-native (#351) * Toggle JSX namespace based on svelte vs svelte-native * add svelte-native-jsx.d.ts to the package * lint fixes --- .../typescript/features/RenameProvider.ts | 2 +- .../src/plugins/typescript/service.ts | 23 ++++++++++++++++--- .../features/CompletionProvider.test.ts | 13 ++++++++--- .../features/DiagnosticsProvider.test.ts | 6 +++++ .../svelte-native/svelte-native.svelte | 12 ++++++++++ .../testfiles/svelte-native/tsconfig.json | 5 ++++ packages/svelte2tsx/package.json | 1 + packages/svelte2tsx/svelte-jsx.d.ts | 2 +- packages/svelte2tsx/svelte-native-jsx.d.ts | 20 ++++++++++++++++ 9 files changed, 76 insertions(+), 8 deletions(-) create mode 100644 packages/language-server/test/plugins/typescript/testfiles/svelte-native/svelte-native.svelte create mode 100644 packages/language-server/test/plugins/typescript/testfiles/svelte-native/tsconfig.json create mode 100644 packages/svelte2tsx/svelte-native-jsx.d.ts diff --git a/packages/language-server/src/plugins/typescript/features/RenameProvider.ts b/packages/language-server/src/plugins/typescript/features/RenameProvider.ts index 21e956781..2b0a6a3c8 100644 --- a/packages/language-server/src/plugins/typescript/features/RenameProvider.ts +++ b/packages/language-server/src/plugins/typescript/features/RenameProvider.ts @@ -127,7 +127,7 @@ export class RenameProviderImpl implements RenameProvider { if ( !renameInfo.canRename || renameInfo.kind === ts.ScriptElementKind.jsxAttribute || - renameInfo.fullDisplayName?.startsWith('JSX.') + renameInfo.fullDisplayName?.includes("JSX.IntrinsicElements") ) { return null; } diff --git a/packages/language-server/src/plugins/typescript/service.ts b/packages/language-server/src/plugins/typescript/service.ts index 4717af2a2..16737b5ee 100644 --- a/packages/language-server/src/plugins/typescript/service.ts +++ b/packages/language-server/src/plugins/typescript/service.ts @@ -66,7 +66,7 @@ export function createLanguageService( const svelteModuleLoader = createSvelteModuleLoader(getSnapshot, compilerOptions); const svelteTsPath = dirname(require.resolve('svelte2tsx')); - const svelteTsxFiles = ['./svelte-shims.d.ts', './svelte-jsx.d.ts'].map((f) => + const svelteTsxFiles = ['./svelte-shims.d.ts', './svelte-jsx.d.ts', './svelte-native-jsx.d.ts'].map((f) => ts.sys.resolvePath(resolve(svelteTsPath, f)), ); @@ -162,8 +162,7 @@ export function createLanguageService( declaration: false, skipLibCheck: true, // these are needed to handle the results of svelte2tsx preprocessing: - jsx: ts.JsxEmit.Preserve, - jsxFactory: 'h', + jsx: ts.JsxEmit.Preserve }; // always let ts parse config to get default compilerOption @@ -203,6 +202,24 @@ export function createLanguageService( ...forcedCompilerOptions, }; + // detect which JSX namespace to use (svelte | svelteNative) if not specified or not compatible + if (!compilerOptions.jsxFactory || !compilerOptions.jsxFactory.startsWith("svelte")) { + //default to regular svelte, this causes the usage of the "svelte.JSX" namespace + compilerOptions.jsxFactory = "svelte.createElement"; + + //override if we detect svelte-native + if (workspacePath) { + try { + const svelteNativePkgInfo = getPackageInfo('svelte-native', workspacePath); + if (svelteNativePkgInfo.path) { + compilerOptions.jsxFactory = "svelteNative.createElement"; + } + } catch (e) { + //we stay regular svelte + } + } + } + return { compilerOptions, files }; } diff --git a/packages/language-server/test/plugins/typescript/features/CompletionProvider.test.ts b/packages/language-server/test/plugins/typescript/features/CompletionProvider.test.ts index fd891f2e6..58faa51e3 100644 --- a/packages/language-server/test/plugins/typescript/features/CompletionProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/CompletionProvider.test.ts @@ -14,6 +14,7 @@ import { } from 'vscode-languageserver'; import { CompletionsProviderImpl, CompletionEntryWithIdentifer } from '../../../../src/plugins/typescript/features/CompletionProvider'; import { LSAndTSDocResolver } from '../../../../src/plugins/typescript/LSAndTSDocResolver'; +import { sortBy } from 'lodash'; const testDir = join(__dirname, '..'); const testFilesDir = join(testDir, 'testfiles'); @@ -182,8 +183,11 @@ describe('CompletionProviderImpl', () => { ]; const ignores = ['tsconfig.json', sourceFile]; - const testfiles = readdirSync(testFilesDir) - .filter((f) => supportedExtensions.includes(extname(f)) && !ignores.includes(f)); + const testfiles = readdirSync(testFilesDir, { withFileTypes: true }) + .filter((f) => f.isDirectory() + || (supportedExtensions.includes(extname(f.name)) + && !ignores.includes(f.name))) + .map(f => f.name); const completions = await completionProvider.getCompletions( document, @@ -194,7 +198,10 @@ describe('CompletionProviderImpl', () => { }, ); - assert.deepStrictEqual(completions?.items.map(item => item.label), testfiles); + assert.deepStrictEqual( + sortBy(completions?.items.map(item => item.label), x => x), + sortBy(testfiles, x => x) + ); }); it('resolve auto import completion (is first import in file)', async () => { diff --git a/packages/language-server/test/plugins/typescript/features/DiagnosticsProvider.test.ts b/packages/language-server/test/plugins/typescript/features/DiagnosticsProvider.test.ts index a323e3c6c..b7efac680 100644 --- a/packages/language-server/test/plugins/typescript/features/DiagnosticsProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/DiagnosticsProvider.test.ts @@ -103,4 +103,10 @@ describe('TypescriptPlugin', () => { assert.deepStrictEqual(diagnostics, []); }); + + it('handles svelte native syntax', async () => { + const { plugin, document } = setup('svelte-native/svelte-native.svelte'); + const diagnostics = await plugin.getDiagnostics(document); + assert.deepStrictEqual(diagnostics, []); + }); }); diff --git a/packages/language-server/test/plugins/typescript/testfiles/svelte-native/svelte-native.svelte b/packages/language-server/test/plugins/typescript/testfiles/svelte-native/svelte-native.svelte new file mode 100644 index 000000000..525783db7 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/testfiles/svelte-native/svelte-native.svelte @@ -0,0 +1,12 @@ + + + + + diff --git a/packages/language-server/test/plugins/typescript/testfiles/svelte-native/tsconfig.json b/packages/language-server/test/plugins/typescript/testfiles/svelte-native/tsconfig.json new file mode 100644 index 000000000..a2a14acdf --- /dev/null +++ b/packages/language-server/test/plugins/typescript/testfiles/svelte-native/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "jsxFactory": "svelteNative" + } +} diff --git a/packages/svelte2tsx/package.json b/packages/svelte2tsx/package.json index 63c594157..fff753498 100644 --- a/packages/svelte2tsx/package.json +++ b/packages/svelte2tsx/package.json @@ -56,6 +56,7 @@ "README.md", "LICENSE", "svelte-jsx.d.ts", + "svelte-native-jsx.d.ts", "svelte-shims.d.ts" ], "dependencies": { diff --git a/packages/svelte2tsx/svelte-jsx.d.ts b/packages/svelte2tsx/svelte-jsx.d.ts index 30e8632c3..b23cf2b75 100644 --- a/packages/svelte2tsx/svelte-jsx.d.ts +++ b/packages/svelte2tsx/svelte-jsx.d.ts @@ -9,7 +9,7 @@ */ - declare namespace JSX { + declare namespace svelte.JSX { /* svelte specific */ interface ElementClass { diff --git a/packages/svelte2tsx/svelte-native-jsx.d.ts b/packages/svelte2tsx/svelte-native-jsx.d.ts new file mode 100644 index 000000000..567989730 --- /dev/null +++ b/packages/svelte2tsx/svelte-native-jsx.d.ts @@ -0,0 +1,20 @@ +declare namespace svelteNative.JSX { + + /* svelte specific */ + interface ElementClass { + $$prop_def: any; + } + + interface ElementAttributesProperty { + $$prop_def: any; // specify the property name to use + } + + // Add empty IntrinsicAttributes to prevent fallback to the one in the JSX namespace + // eslint-disable-next-line @typescript-eslint/no-empty-interface + interface IntrinsicAttributes { + } + + interface IntrinsicElements { + [name: string]: { [name: string]: any }; + } +} \ No newline at end of file