Skip to content

Commit

Permalink
Merge branch 'sveltejs:master' into ts-5_7
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonlyu123 authored Nov 14, 2024
2 parents 1846f87 + 77160ff commit aceceac
Show file tree
Hide file tree
Showing 18 changed files with 108 additions and 59 deletions.
4 changes: 4 additions & 0 deletions packages/language-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,10 @@ Enable code actions for Svelte. _Default_: `true`

Enable selection range for Svelte. _Default_: `true`

##### `svelte.plugin.svelte.runesLegacyModeCodeLens.enable`

Whether or not to show a code lens at the top of Svelte files indicating if they are in runes mode or legacy mode. Only visible in Svelte 5 projects. _Default_: `true`

##### `svelte.plugin.svelte.defaultScriptLanguage`

The default language to use when generating new script tags in Svelte. _Default_: `none`
Expand Down
2 changes: 1 addition & 1 deletion packages/language-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
"globrex": "^0.1.2",
"lodash": "^4.17.21",
"prettier": "~3.3.3",
"prettier-plugin-svelte": "^3.2.6",
"prettier-plugin-svelte": "^3.2.8",
"svelte": "^4.2.19",
"svelte2tsx": "workspace:~",
"typescript": "^5.7.1-rc",
Expand Down
2 changes: 2 additions & 0 deletions packages/language-server/src/ls-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const defaultLSConfig: LSConfig = {
hover: { enable: true },
codeActions: { enable: true },
selectionRange: { enable: true },
runesLegacyModeCodeLens: { enable: true },
defaultScriptLanguage: 'none'
}
};
Expand Down Expand Up @@ -188,6 +189,7 @@ export interface LSSvelteConfig {
selectionRange: {
enable: boolean;
};
runesLegacyModeCodeLens: { enable: boolean };
defaultScriptLanguage: 'none' | 'ts';
}

Expand Down
5 changes: 3 additions & 2 deletions packages/language-server/src/plugins/PluginHost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -633,12 +633,13 @@ export class PluginHost implements LSProvider, OnWatchFileChanges {
throw new Error('Cannot call methods on an unopened document');
}

return await this.execute<CodeLens[]>(
const result = await this.execute<CodeLens[]>(
'getCodeLens',
[document],
ExecuteMode.FirstNonNull,
ExecuteMode.Collect,
'smart'
);
return flatten(result.filter(Boolean));
}

async getFoldingRanges(textDocument: TextDocumentIdentifier): Promise<FoldingRange[]> {
Expand Down
17 changes: 13 additions & 4 deletions packages/language-server/src/plugins/svelte/SveltePlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ export class SveltePlugin
constructor(private configManager: LSConfigManager) {}

async getCodeLens(document: Document): Promise<CodeLens[] | null> {
if (!this.featureEnabled('runesLegacyModeCodeLens')) return null;

const doc = await this.getSvelteDoc(document);
if (!doc.isSvelte5) return null;

Expand Down Expand Up @@ -125,11 +127,9 @@ export class SveltePlugin
/**
* Prettier v2 can't use v3 plugins and vice versa. Therefore, we need to check
* which version of prettier is used in the workspace and import the correct
* version of the Svelte plugin. If user uses Prettier >= 3 and has no Svelte plugin
* then fall back to our built-in versions which are both v2 and compatible with
* version of the Svelte plugin. If user uses Prettier < 3 and has no Svelte plugin
* then fall back to our built-in versions which are both v3 and compatible with
* each other.
* TODO switch this around at some point to load Prettier v3 by default because it's
* more likely that users have that installed.
*/
const importFittingPrettier = async () => {
const getConfig = async (p: any) => {
Expand Down Expand Up @@ -204,6 +204,15 @@ export class SveltePlugin
return [];
}

if (isFallback || !(await hasSveltePluginLoaded(prettier, resolvedPlugins))) {
// If the user uses Svelte 5 but doesn't have prettier installed, we need to provide
// the compiler path to the plugin so it can use its parser method; else it will crash.
const svelteCompilerInfo = getPackageInfo('svelte', filePath);
if (svelteCompilerInfo.version.major >= 5) {
config.svelte5CompilerPath = svelteCompilerInfo.path + '/compiler';
}
}

// Prettier v3 format is async, v2 is not
const formattedCode = await prettier.format(document.getText(), {
...config,
Expand Down
22 changes: 15 additions & 7 deletions packages/language-server/src/plugins/svelte/features/SvelteTags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Await blocks allow you to branch on the three possible states of a Promise — p
\`{#await expression}...{:then name}...{/await}\`\\
\`{#await expression then name}...{/await}\`\\
\\
https://svelte.dev/docs#template-syntax-await
https://svelte.dev/docs/svelte/await
`,
each: `\`{#each ...}\`\\
Iterating over lists of values can be done with an each block.
Expand All @@ -33,7 +33,7 @@ Iterating over lists of values can be done with an each block.
\`{#each expression as name, index (key)}...{/each}\`\\
\`{#each expression as name}...{:else}...{/each}\`\\
\\
https://svelte.dev/docs#template-syntax-each
https://svelte.dev/docs/svelte/each
`,
if: `\`{#if ...}\`\\
Content that is conditionally rendered can be wrapped in an if block.
Expand All @@ -42,7 +42,7 @@ Content that is conditionally rendered can be wrapped in an if block.
\`{#if expression}...{:else if expression}...{/if}\`\\
\`{#if expression}...{:else}...{/if}\`\\
\\
https://svelte.dev/docs#template-syntax-if
https://svelte.dev/docs/svelte/if
`,
key: `\`{#key expression}...{/key}\`\\
Key blocks destroy and recreate their contents when the value of an expression changes.\\
Expand All @@ -51,14 +51,22 @@ When used around components, this will cause them to be reinstantiated and reini
#### Usage:
\`{#key expression}...{/key}\`\\
\\
https://svelte.dev/docs#template-syntax-key
https://svelte.dev/docs/svelte/key
`,
snippet: `\`{#snippet identifier(parameter)}...{/snippet}\`\\
Snippets allow you to create reusable UI blocks you can render with the {@render ...} tag.
They also function as slot props for components.
#### Usage:
\`{#snippet identifier(parameter)}...{/snippet}\`\\
\\
https://svelte.dev/docs/svelte/snippet
`,
render: `\`{@render ...}\`\\
Renders a snippet with the given parameters.
#### Usage:
\`{@render identifier(parameter)}\`\\
\\
https://svelte.dev/docs/svelte/@render
`,
html:
`\`{@html ...}\`\\
Expand All @@ -72,7 +80,7 @@ If the data comes from an untrusted source, you must sanitize it, ` +
#### Usage:
\`{@html expression}\`\\
\\
https://svelte.dev/docs#template-syntax-html
https://svelte.dev/docs/svelte/@html
`,
debug:
`\`{@debug ...}\`\\
Expand All @@ -84,14 +92,14 @@ It accepts a comma-separated list of variable names (not arbitrary expressions).
\`{@debug}\`
\`{@debug var1, var2, ..., varN}\`\\
\\
https://svelte.dev/docs#template-syntax-debug
https://svelte.dev/docs/svelte/@debug
`,
const: `\`{@const ...}\`\\
Defines a local constant}\\
#### Usage:
\`{@const a = b + c}\`\\
\\
https://svelte.dev/docs/special-tags#const
https://svelte.dev/docs/svelte/@const
`
};

Expand Down
6 changes: 6 additions & 0 deletions packages/svelte-vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,12 @@
"title": "Svelte: Rename",
"description": "Enable rename/move Svelte files functionality"
},
"svelte.plugin.svelte.runesLegacyModeCodeLens.enable": {
"type": "boolean",
"default": true,
"title": "Svelte: Legacy/Runes mode Code Lens",
"description": "Show a code lens at the top of Svelte files indicating if they are in runes mode or legacy mode. Only visible in Svelte 5 projects."
},
"svelte.plugin.svelte.defaultScriptLanguage": {
"type": "string",
"default": "none",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,38 @@ const defaultScriptTemplate = `
/** @type {import('./$types').LayoutData} */
export let data;
</script>
<slot />
`;

const tsSv5ScriptTemplate = `
<script lang="ts">
import type { Snippet } from 'svelte';
import type { LayoutData } from './$types';
let { data }: LayoutData = $props();
let { data, children }: { data: LayoutData, children: Snippet } = $props();
</script>
{@render children()}
`;

const tsScriptTemplate = `
<script lang="ts">
import type { LayoutData } from './$types';
export let data: LayoutData;
</script>
<slot />
`;

const jsSv5ScriptTemplate = `
<script>
/** @type {import('./$types').LayoutData} */
let { data } = $props();
/** @type {{ data: import('./$types').LayoutData, children: import('svelte').Snippet }} */
let { data, children } = $props();
</script>
{@render children()}
`;

const scriptTemplate: ReadonlyMap<ProjectType, string> = new Map([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,22 @@ const defaultScriptTemplate = `
const tsSv5ScriptTemplate = `
<script lang="ts">
import type { PageData } from './$types';
let { data }: PageData = $props();
let { data }: { data: PageData } = $props();
</script>
`;

const tsScriptTemplate = `
<script lang="ts">
import type { PageData } from './$types';
export let data: PageData;
</script>
`;

const jsSv5ScriptTemplate = `
<script>
/** @type {import('./$types').PageData} */
/** @type {{ data: import('./$types').PageData }} */
let { data } = $props();
</script>
`;
Expand Down
52 changes: 31 additions & 21 deletions packages/svelte2tsx/src/svelte2tsx/nodes/ExportedNames.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,25 +277,36 @@ export class ExportedNames {
props.push(`form: import('./$types.js').ActionData`);
}
} else if (element.initializer) {
const type = ts.isAsExpression(element.initializer)
? element.initializer.type.getText()
: ts.isStringLiteral(element.initializer)
? 'string'
: ts.isNumericLiteral(element.initializer)
? 'number'
: element.initializer.kind === ts.SyntaxKind.TrueKeyword ||
element.initializer.kind === ts.SyntaxKind.FalseKeyword
? 'boolean'
: ts.isIdentifier(element.initializer)
? `typeof ${element.initializer.text}`
: ts.isObjectLiteralExpression(element.initializer)
? 'Record<string, unknown>'
: ts.isArrayLiteralExpression(element.initializer)
? 'unknown[]'
: 'unknown';
const initializer =
ts.isCallExpression(element.initializer) &&
ts.isIdentifier(element.initializer.expression) &&
element.initializer.expression.text === '$bindable'
? element.initializer.arguments[0]
: element.initializer;
const type = !initializer
? 'any'
: ts.isAsExpression(initializer)
? initializer.type.getText()
: ts.isStringLiteral(initializer)
? 'string'
: ts.isNumericLiteral(initializer)
? 'number'
: initializer.kind === ts.SyntaxKind.TrueKeyword ||
initializer.kind === ts.SyntaxKind.FalseKeyword
? 'boolean'
: ts.isIdentifier(initializer) &&
initializer.text !== 'undefined'
? `typeof ${initializer.text}`
: ts.isArrowFunction(initializer)
? 'Function'
: ts.isObjectLiteralExpression(initializer)
? 'Record<string, any>'
: ts.isArrayLiteralExpression(initializer)
? 'any[]'
: 'any';
props.push(`${name}?: ${type}`);
} else {
props.push(`${name}: unknown`);
props.push(`${name}: any`);
}
}
}
Expand All @@ -306,15 +317,14 @@ export class ExportedNames {

if (props.length > 0) {
propsStr =
`{ ${props.join(', ')} }` +
(withUnknown ? ' & Record<string, unknown>' : '');
`{ ${props.join(', ')} }` + (withUnknown ? ' & Record<string, any>' : '');
} else if (withUnknown) {
propsStr = 'Record<string, unknown>';
propsStr = 'Record<string, any>';
} else {
propsStr = 'Record<string, never>';
}
} else {
propsStr = 'Record<string, unknown>';
propsStr = 'Record<string, any>';
}

// Create a virtual type alias for the unnamed generic and reuse it for the props return type
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
///<reference types="svelte" />
;function render() {

let/** @typedef {{ a: unknown, b?: boolean, c?: number, d?: string, e?: unknown, f?: Record<string, unknown>, g?: typeof foo, h?: unknown[] }} $$ComponentProps *//** @type {$$ComponentProps} */ { a, b = true, c = 1, d = '', e = null, f = {}, g = foo, h = [] } = $props();
let/** @typedef {{ a: any, b?: boolean, c?: number, d?: string, e?: any, f?: Record<string, any>, g?: typeof foo, h?: any[], i?: any, j?: any, k?: number, l?: Function }} $$ComponentProps *//** @type {$$ComponentProps} */ { a, b = true, c = 1, d = '', e = null, f = {}, g = foo, h = [], i = undefined, j = $bindable(), k = $bindable(1), l = () => {} } = $props();
;
async () => {};
return { props: /** @type {$$ComponentProps} */({}), exports: {}, bindings: __sveltets_$$bindings(''), slots: {}, events: {} }}
return { props: /** @type {$$ComponentProps} */({}), exports: {}, bindings: __sveltets_$$bindings('j', 'k'), slots: {}, events: {} }}
const Input__SvelteComponent_ = __sveltets_2_fn_component(render());
type Input__SvelteComponent_ = ReturnType<typeof Input__SvelteComponent_>;
export default Input__SvelteComponent_;
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<script>
let { a, b = true, c = 1, d = '', e = null, f = {}, g = foo, h = [] } = $props();
let { a, b = true, c = 1, d = '', e = null, f = {}, g = foo, h = [], i = undefined, j = $bindable(), k = $bindable(1), l = () => {} } = $props();
</script>
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
///<reference types="svelte" />
;function render() {

let/** @typedef {{ a: unknown, b?: unknown }} $$ComponentProps *//** @type {$$ComponentProps} */ { a, b = $bindable() } = $props();
let/** @typedef {{ a: any, b?: any }} $$ComponentProps *//** @type {$$ComponentProps} */ { a, b = $bindable() } = $props();
;
async () => {};
return { props: /** @type {$$ComponentProps} */({}), exports: {}, bindings: __sveltets_$$bindings('b'), slots: {}, events: {} }}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
///<reference types="svelte" />
;function render() {

let/** @typedef {{ props: unknown }} $$ComponentProps *//** @type {$$ComponentProps} */ { props } = $props();
let/** @typedef {{ props: any }} $$ComponentProps *//** @type {$$ComponentProps} */ { props } = $props();
let state = $state(0);
let derived = $derived(state * 2);
;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
///<reference types="svelte" />
;function render() {
/*Ωignore_startΩ*/;type $$ComponentProps = { a: unknown, b?: boolean, c?: number, d?: string, e?: unknown, f?: Record<string, unknown>, g?: typeof foo, h?: Bar, i?: Baz, j?: unknown[] };/*Ωignore_endΩ*/
let { a, b = true, c = 1, d = '', e = null, f = {}, g = foo, h = null as Bar, i = null as any as Baz, j = [] }: $$ComponentProps = $props();
/*Ωignore_startΩ*/;type $$ComponentProps = { a: any, b?: boolean, c?: number, d?: string, e?: any, f?: Record<string, any>, g?: typeof foo, h?: Bar, i?: Baz, j?: any[], k?: any, l?: any, m?: number, n?: Function };/*Ωignore_endΩ*/
let { a, b = true, c = 1, d = '', e = null, f = {}, g = foo, h = null as Bar, i = null as any as Baz, j = [], k = undefined, l = $bindable(), m = $bindable(1), n = () => {} }: $$ComponentProps = $props();
;
async () => {};
return { props: {} as any as $$ComponentProps, exports: {}, bindings: __sveltets_$$bindings(''), slots: {}, events: {} }}
return { props: {} as any as $$ComponentProps, exports: {}, bindings: __sveltets_$$bindings('l', 'm'), slots: {}, events: {} }}
const Input__SvelteComponent_ = __sveltets_2_fn_component(render());
type Input__SvelteComponent_ = ReturnType<typeof Input__SvelteComponent_>;
export default Input__SvelteComponent_;
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<script>
let { a, b = true, c = 1, d = '', e = null, f = {}, g = foo, h = null as Bar, i = null as any as Baz, j = [] } = $props();
let { a, b = true, c = 1, d = '', e = null, f = {}, g = foo, h = null as Bar, i = null as any as Baz, j = [], k = undefined, l = $bindable(), m = $bindable(1), n = () => {} } = $props();
</script>
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
///<reference types="svelte" />
;function render() {
/*Ωignore_startΩ*/;type $$ComponentProps = { a: unknown, b?: unknown, c?: number };/*Ωignore_endΩ*/
/*Ωignore_startΩ*/;type $$ComponentProps = { a: any, b?: any, c?: number };/*Ωignore_endΩ*/
let { a, b = $bindable(), c = $bindable(0) as number }: $$ComponentProps = $props();
;
async () => {};
Expand Down
Loading

0 comments on commit aceceac

Please sign in to comment.