From 98a72f50684ff18af5595f0eec6b91770626adb4 Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Tue, 2 Jan 2024 14:18:59 +0100 Subject: [PATCH] chore: check in types (#9863) To ensure that changes to code/types doesn't result in unwanted changes in type generation, or that bumps to dts-buddy don't cause unwanted regressions, we're checking in the generated types. Types should be committed as-is (don't format it with prettier!). CI is enhanced to check that git sees no changed files after generating the types, which would mean types have changed. --- .github/workflows/ci.yml | 9 +- .github/workflows/release.yml | 6 +- CONTRIBUTING.md | 6 +- packages/svelte/.gitignore | 3 +- packages/svelte/package.json | 5 +- .../scripts/{build.js => generate-types.js} | 0 packages/svelte/types/index.d.ts | 2570 +++++++++++++++++ pnpm-lock.yaml | 10 +- 8 files changed, 2598 insertions(+), 11 deletions(-) rename packages/svelte/scripts/{build.js => generate-types.js} (100%) create mode 100644 packages/svelte/types/index.d.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 08820f0ed3..7c3969cd54 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,4 +50,11 @@ jobs: with: node-version: 18 cache: pnpm - - run: 'pnpm i && pnpm check && pnpm lint' + - name: install + run: pnpm install --frozen-lockfile + - name: type check + run: pnpm check + - name: lint + run: pnpm lint + - name: build and check generated types + run: pnpm build && { [ "`git status --porcelain=v1`" == "" ] || (echo "Generated types have changed — please regenerate types locally and commit the changes after you have reviewed them"; git diff; exit 1); } diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 24b1229b42..7810870670 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,7 +28,11 @@ jobs: node-version: 18.x cache: pnpm - - run: pnpm install --frozen-lockfile + - name: Install + run: pnpm install --frozen-lockfile + + - name: Build + run: pnpm build && { [ "`git status --porcelain=v1`" == "" ] || (echo "Generated types have changed — please regenerate types locally and commit the changes after you have reviewed them"; git diff; exit 1); } - name: Create Release Pull Request or Publish to npm id: changesets diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 167a62646e..613551574f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -133,6 +133,10 @@ To typecheck the codebase, run `pnpm check` inside `packages/svelte`. To typeche - `snake_case` for internal variable names and methods. - `camelCase` for public variable names and methods. +### Generating types + +Types are auto-generated from the source, but the result is checked in to ensure no accidental changes slip through. Run `pnpm generate:types` to regenerate the types. + ### Sending your pull request Please make sure the following is done when submitting a pull request: @@ -141,7 +145,7 @@ Please make sure the following is done when submitting a pull request: 1. Make sure your code lints (`pnpm lint`). 1. Make sure your tests pass (`pnpm test`). -All pull requests should be opened against the `main` branch. Make sure the PR does only one thing, otherwise please split it. +All pull requests should be opened against the `main` branch. Make sure the PR does only one thing, otherwise please split it. If this change should contribute to a version bump, run `npx changeset` at the root of the repository after a code change and select the appropriate packages. #### Breaking changes diff --git a/packages/svelte/.gitignore b/packages/svelte/.gitignore index faa8892951..e4925570e5 100644 --- a/packages/svelte/.gitignore +++ b/packages/svelte/.gitignore @@ -1,4 +1,5 @@ -/types +/types/*.map +/types/compiler /compiler.cjs /action.d.ts diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 50fb4f09c8..3cde08871a 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -90,11 +90,12 @@ "templating" ], "scripts": { - "build": "rollup -c && node scripts/build.js && node scripts/check-treeshakeability.js", + "build": "rollup -c && pnpm generate:types && node scripts/check-treeshakeability.js", "dev": "rollup -cw", "check": "tsc && cd ./tests/types && tsc", "check:watch": "tsc --watch", "generate:version": "node ./scripts/generate-version.js", + "generate:types": "node ./scripts/generate-types.js", "prepublishOnly": "pnpm build" }, "devDependencies": { @@ -106,7 +107,7 @@ "@rollup/plugin-virtual": "^3.0.2", "@types/aria-query": "^5.0.3", "@types/estree": "^1.0.5", - "dts-buddy": "^0.4.0", + "dts-buddy": "^0.4.3", "esbuild": "^0.19.2", "rollup": "^4.1.5", "source-map": "^0.7.4", diff --git a/packages/svelte/scripts/build.js b/packages/svelte/scripts/generate-types.js similarity index 100% rename from packages/svelte/scripts/build.js rename to packages/svelte/scripts/generate-types.js diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts new file mode 100644 index 0000000000..4db8209706 --- /dev/null +++ b/packages/svelte/types/index.d.ts @@ -0,0 +1,2570 @@ +declare module 'svelte' { + // This should contain all the public interfaces (not all of them are actually importable, check current Svelte for which ones are). + + /** + * @deprecated Svelte components were classes in Svelte 4. In Svelte 5, thy are not anymore. + * Use `mount` or `createRoot` instead to instantiate components. + * See [breaking changes](https://svelte-5-preview.vercel.app/docs/breaking-changes#components-are-no-longer-classes) + * for more info. + */ + export interface ComponentConstructorOptions< + Props extends Record = Record + > { + target: Element | Document | ShadowRoot; + anchor?: Element; + props?: Props; + context?: Map; + hydrate?: boolean; + intro?: boolean; + $$inline?: boolean; + } + + // Utility type for ensuring backwards compatibility on a type level: If there's a default slot, add 'children' to the props if it doesn't exist there already + type PropsWithChildren = Props & + (Props extends { children?: any } + ? {} + : Slots extends { default: any } + ? { children?: Snippet } + : {}); + + /** + * Can be used to create strongly typed Svelte components. + * + * #### Example: + * + * You have component library on npm called `component-library`, from which + * you export a component called `MyComponent`. For Svelte+TypeScript users, + * you want to provide typings. Therefore you create a `index.d.ts`: + * ```ts + * import { SvelteComponent } from "svelte"; + * export class MyComponent extends SvelteComponent<{foo: string}> {} + * ``` + * Typing this makes it possible for IDEs like VS Code with the Svelte extension + * to provide intellisense and to use the component like this in a Svelte file + * with TypeScript: + * ```svelte + * + * + * ``` + * + * This was the base class for Svelte components in Svelte 4. Svelte 5+ components + * are completely different under the hood. You should only use this type for typing, + * not actually instantiate components with `new` - use `mount` or `createRoot` instead. + * See [breaking changes](https://svelte-5-preview.vercel.app/docs/breaking-changes#components-are-no-longer-classes) + * for more info. + */ + export class SvelteComponent< + Props extends Record = any, + Events extends Record = any, + Slots extends Record = any + > { + [prop: string]: any; + /** + * @deprecated This constructor only exists when using the `asClassComponent` compatibility helper, which + * is a stop-gap solution. Migrate towards using `mount` or `createRoot` instead. See + * https://svelte-5-preview.vercel.app/docs/breaking-changes#components-are-no-longer-classes for more info. + */ + constructor(options: ComponentConstructorOptions>); + /** + * For type checking capabilities only. + * Does not exist at runtime. + * ### DO NOT USE! + * */ + $$prop_def: PropsWithChildren; + /** + * For type checking capabilities only. + * Does not exist at runtime. + * ### DO NOT USE! + * + * */ + $$events_def: Events; + /** + * For type checking capabilities only. + * Does not exist at runtime. + * ### DO NOT USE! + * + * */ + $$slot_def: Slots; + + /** + * @deprecated This method only exists when using one of the legacy compatibility helpers, which + * is a stop-gap solution. See https://svelte-5-preview.vercel.app/docs/breaking-changes#components-are-no-longer-classes + * for more info. + */ + $destroy(): void; + + /** + * @deprecated This method only exists when using one of the legacy compatibility helpers, which + * is a stop-gap solution. See https://svelte-5-preview.vercel.app/docs/breaking-changes#components-are-no-longer-classes + * for more info. + */ + $on>( + type: K, + callback: (e: Events[K]) => void + ): () => void; + + /** + * @deprecated This method only exists when using one of the legacy compatibility helpers, which + * is a stop-gap solution. See https://svelte-5-preview.vercel.app/docs/breaking-changes#components-are-no-longer-classes + * for more info. + */ + $set(props: Partial): void; + } + + /** + * @deprecated Use `SvelteComponent` instead. See TODO for more information. + */ + export class SvelteComponentTyped< + Props extends Record = any, + Events extends Record = any, + Slots extends Record = any + > extends SvelteComponent {} + + /** + * Convenience type to get the events the given component expects. Example: + * ```html + * + * + * + * ``` + */ + export type ComponentEvents = Comp extends SvelteComponent< + any, + infer Events + > + ? Events + : never; + + /** + * Convenience type to get the props the given component expects. Example: + * ```html + * + * ``` + */ + export type ComponentProps = Comp extends SvelteComponent + ? Props + : never; + + /** + * Convenience type to get the type of a Svelte component. Useful for example in combination with + * dynamic components using ``. + * + * Example: + * ```html + * + * + * + * + * ``` + */ + export type ComponentType = (new ( + options: ComponentConstructorOptions< + Comp extends SvelteComponent ? Props : Record + > + ) => Comp) & { + /** The custom element version of the component. Only present if compiled with the `customElement` compiler option */ + element?: typeof HTMLElement; + }; + + const SnippetReturn: unique symbol; + + /** + * The type of a `#snippet` block. You can use it to (for example) express that your component expects a snippet of a certain type: + * ```ts + * let { banner } = $props<{ banner: Snippet<{ text: string }> }>(); + * ``` + * You can only call a snippet through the `{@render ...}` tag. + */ + export interface Snippet { + (arg: T): typeof SnippetReturn & { + _: 'functions passed to {@render ...} tags must use the `Snippet` type imported from "svelte"'; + }; + } + + interface DispatchOptions { + cancelable?: boolean; + } + + export interface EventDispatcher> { + // Implementation notes: + // - undefined extends X instead of X extends undefined makes this work better with both strict and nonstrict mode + // - | null | undefined is added for convenience, as they are equivalent for the custom event constructor (both result in a null detail) + ( + ...args: null extends EventMap[Type] + ? [type: Type, parameter?: EventMap[Type] | null | undefined, options?: DispatchOptions] + : undefined extends EventMap[Type] + ? [type: Type, parameter?: EventMap[Type] | null | undefined, options?: DispatchOptions] + : [type: Type, parameter: EventMap[Type], options?: DispatchOptions] + ): boolean; + } + /** + * The `onMount` function schedules a callback to run as soon as the component has been mounted to the DOM. + * It must be called during the component's initialisation (but doesn't need to live *inside* the component; + * it can be called from an external module). + * + * If a function is returned _synchronously_ from `onMount`, it will be called when the component is unmounted. + * + * `onMount` does not run inside a [server-side component](/docs#run-time-server-side-component-api). + * + * https://svelte.dev/docs/svelte#onmount + * */ + export function onMount(fn: () => NotFunction | Promise> | (() => any)): void; + /** + * Retrieves the context that belongs to the closest parent component with the specified `key`. + * Must be called during component initialisation. + * + * https://svelte.dev/docs/svelte#getcontext + * */ + export function getContext(key: any): T; + /** + * Associates an arbitrary `context` object with the current component and the specified `key` + * and returns that object. The context is then available to children of the component + * (including slotted content) with `getContext`. + * + * Like lifecycle functions, this must be called during component initialisation. + * + * https://svelte.dev/docs/svelte#setcontext + * */ + export function setContext(key: any, context: T): T; + /** + * Checks whether a given `key` has been set in the context of a parent component. + * Must be called during component initialisation. + * + * https://svelte.dev/docs/svelte#hascontext + * */ + export function hasContext(key: any): boolean; + /** + * Retrieves the whole context map that belongs to the closest parent component. + * Must be called during component initialisation. Useful, for example, if you + * programmatically create a component and want to pass the existing context to it. + * + * https://svelte.dev/docs/svelte#getallcontexts + * */ + export function getAllContexts = Map>(): T; + /** + * Creates an event dispatcher that can be used to dispatch [component events](/docs#template-syntax-component-directives-on-eventname). + * Event dispatchers are functions that can take two arguments: `name` and `detail`. + * + * Component events created with `createEventDispatcher` create a + * [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent). + * These events do not [bubble](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture). + * The `detail` argument corresponds to the [CustomEvent.detail](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/detail) + * property and can contain any type of data. + * + * The event dispatcher can be typed to narrow the allowed event names and the type of the `detail` argument: + * ```ts + * const dispatch = createEventDispatcher<{ + * loaded: never; // does not take a detail argument + * change: string; // takes a detail argument of type string, which is required + * optional: number | null; // takes an optional detail argument of type number + * }>(); + * ``` + * + * https://svelte.dev/docs/svelte#createeventdispatcher + * */ + export function createEventDispatcher = any>(): EventDispatcher; + /** + * Schedules a callback to run immediately before the component is updated after any state change. + * + * The first time the callback runs will be before the initial `onMount`. + * + * In runes mode use `$effect.pre` instead. + * + * https://svelte.dev/docs/svelte#beforeupdate + * @deprecated Use `$effect.pre` instead — see https://svelte-5-preview.vercel.app/docs/deprecations#beforeupdate-and-afterupdate + * */ + export function beforeUpdate(fn: () => void): void; + /** + * Schedules a callback to run immediately after the component has been updated. + * + * The first time the callback runs will be after the initial `onMount`. + * + * In runes mode use `$effect` instead. + * + * https://svelte.dev/docs/svelte#afterupdate + * @deprecated Use `$effect` instead — see https://svelte-5-preview.vercel.app/docs/deprecations#beforeupdate-and-afterupdate + * */ + export function afterUpdate(fn: () => void): void; + /** + * Anything except a function + */ + type NotFunction = T extends Function ? never : T; + /** + * Mounts the given component to the given target and returns a handle to the component's public accessors + * as well as a `$set` and `$destroy` method to update the props of the component or destroy it. + * + * If you don't need to interact with the component after mounting, use `mount` instead to save some bytes. + * + * */ + export function createRoot, Exports extends Record | undefined, Events extends Record>(component: { + new (options: ComponentConstructorOptions | undefined; + })>): SvelteComponent; + }, options: { + target: Node; + props?: Props | undefined; + events?: Events | undefined; + context?: Map | undefined; + intro?: boolean | undefined; + recover?: false | undefined; + }): Exports & { + $destroy: () => void; + $set: (props: Partial) => void; + }; + /** + * Mounts the given component to the given target and returns the accessors of the component and a function to destroy it. + * + * If you need to interact with the component after mounting, use `createRoot` instead. + * + * */ + export function mount, Exports extends Record | undefined, Events extends Record>(component: { + new (options: ComponentConstructorOptions | undefined; + })>): SvelteComponent; + }, options: { + target: Node; + props?: Props | undefined; + events?: Events | undefined; + context?: Map | undefined; + intro?: boolean | undefined; + recover?: false | undefined; + }): [Exports, () => void]; + /** + * Synchronously flushes any pending state changes and those that result from it. + * */ + export function flushSync(fn?: (() => void) | undefined): void; + /** + * Returns a promise that resolves once any pending state changes have been applied. + * */ + export function tick(): Promise; + /** + * Use `untrack` to prevent something from being treated as an `$effect`/`$derived` dependency. + * + * https://svelte-5-preview.vercel.app/docs/functions#untrack + * */ + export function untrack(fn: () => T): T; + /** + * Schedules a callback to run immediately before the component is unmounted. + * + * Out of `onMount`, `beforeUpdate`, `afterUpdate` and `onDestroy`, this is the + * only one that runs inside a server-side component. + * + * https://svelte.dev/docs/svelte#ondestroy + * */ + export function onDestroy(fn: () => any): void; + export function unstate(value: T): T; +} + +declare module 'svelte/action' { + /** + * Actions can return an object containing the two properties defined in this interface. Both are optional. + * - update: An action can have a parameter. This method will be called whenever that parameter changes, + * immediately after Svelte has applied updates to the markup. `ActionReturn` and `ActionReturn` both + * mean that the action accepts no parameters. + * - destroy: Method that is called after the element is unmounted + * + * Additionally, you can specify which additional attributes and events the action enables on the applied element. + * This applies to TypeScript typings only and has no effect at runtime. + * + * Example usage: + * ```ts + * interface Attributes { + * newprop?: string; + * 'on:event': (e: CustomEvent) => void; + * } + * + * export function myAction(node: HTMLElement, parameter: Parameter): ActionReturn { + * // ... + * return { + * update: (updatedParameter) => {...}, + * destroy: () => {...} + * }; + * } + * ``` + * + * Docs: https://svelte.dev/docs/svelte-action + */ + export interface ActionReturn< + Parameter = undefined, + Attributes extends Record = Record + > { + update?: (parameter: Parameter) => void; + destroy?: () => void; + /** + * ### DO NOT USE THIS + * This exists solely for type-checking and has no effect at runtime. + * Set this through the `Attributes` generic instead. + */ + $$_attributes?: Attributes; + } + + /** + * Actions are functions that are called when an element is created. + * You can use this interface to type such actions. + * The following example defines an action that only works on `
` elements + * and optionally accepts a parameter which it has a default value for: + * ```ts + * export const myAction: Action = (node, param = { someProperty: true }) => { + * // ... + * } + * ``` + * `Action` and `Action` both signal that the action accepts no parameters. + * + * You can return an object with methods `update` and `destroy` from the function and type which additional attributes and events it has. + * See interface `ActionReturn` for more details. + * + * Docs: https://svelte.dev/docs/svelte-action + */ + export interface Action< + Element = HTMLElement, + Parameter = undefined, + Attributes extends Record = Record + > { + ( + ...args: undefined extends Parameter + ? [node: Node, parameter?: Parameter] + : [node: Node, parameter: Parameter] + ): void | ActionReturn; + } + + // Implementation notes: + // - undefined extends X instead of X extends undefined makes this work better with both strict and nonstrict mode +} + +declare module 'svelte/animate' { + // todo: same as Transition, should it be shared? + export interface AnimationConfig { + delay?: number; + duration?: number; + easing?: (t: number) => number; + css?: (t: number, u: number) => string; + tick?: (t: number, u: number) => void; + } + + export interface FlipParams { + delay?: number; + duration?: number | ((len: number) => number); + easing?: (t: number) => number; + } + /** + * The flip function calculates the start and end position of an element and animates between them, translating the x and y values. + * `flip` stands for [First, Last, Invert, Play](https://aerotwist.com/blog/flip-your-animations/). + * + * https://svelte.dev/docs/svelte-animate#flip + * */ + export function flip(node: Element, { from, to }: { + from: DOMRect; + to: DOMRect; + }, params?: FlipParams): AnimationConfig; +} + +declare module 'svelte/compiler' { + import type { AssignmentExpression, ClassDeclaration, Expression, FunctionDeclaration, Identifier, ImportDeclaration, ArrayExpression, MemberExpression, ObjectExpression, Pattern, ArrowFunctionExpression, VariableDeclaration, VariableDeclarator, FunctionExpression, Node, Program } from 'estree'; + import type { Location } from 'locate-character'; + import type { SourceMap } from 'magic-string'; + import type { Context } from 'zimmerframe'; + /** + * `compile` converts your `.svelte` source code into a JavaScript module that exports a component + * + * https://svelte.dev/docs/svelte-compiler#svelte-compile + * @param source The component source code + * @param options The compiler options + * */ + export function compile(source: string, options: CompileOptions): CompileResult; + /** + * `compileModule` takes your JavaScript source code containing runes, and turns it into a JavaScript module. + * + * https://svelte.dev/docs/svelte-compiler#svelte-compile + * @param source The component source code + * */ + export function compileModule(source: string, options: ModuleCompileOptions): CompileResult; + /** + * The parse function parses a component, returning only its abstract syntax tree. + * + * The `modern` option (`false` by default in Svelte 5) makes the parser return a modern AST instead of the legacy AST. + * `modern` will become `true` by default in Svelte 6, and the option will be removed in Svelte 7. + * + * https://svelte.dev/docs/svelte-compiler#svelte-parse + * */ + export function parse(source: string, options?: { + filename?: string | undefined; + modern?: boolean | undefined; + } | undefined): SvelteNode | LegacySvelteNode; + /** + * @deprecated Replace this with `import { walk } from 'estree-walker'` + * */ + function walk(): never; + /** The return value of `compile` from `svelte/compiler` */ + interface CompileResult { + /** The compiled JavaScript */ + js: { + /** The generated code */ + code: string; + /** A source map */ + map: SourceMap; + }; + /** The compiled CSS */ + css: null | { + /** The generated code */ + code: string; + /** A source map */ + map: SourceMap; + }; + /** + * An array of warning objects that were generated during compilation. Each warning has several properties: + * - `code` is a string identifying the category of warning + * - `message` describes the issue in human-readable terms + * - `start` and `end`, if the warning relates to a specific location, are objects with `line`, `column` and `character` properties + */ + warnings: Warning[]; + /** + * Metadata about the compiled component + */ + metadata: { + /** + * Whether the file was compiled in runes mode, either because of an explicit option or inferred from usage. + * For `compileModule`, this is always `true` + */ + runes: boolean; + }; + } + + interface Warning { + start?: Location; + end?: Location; + // TODO there was pos: number in Svelte 4 - do we want to add it back? + code: string; + message: string; + filename?: string; + } + + interface CompileError_1 extends Error { + code: string; + filename?: string; + position?: [number, number]; + start?: Location; + end?: Location; + } + + type CssHashGetter = (args: { + name: string; + filename: string | undefined; + css: string; + hash: (input: string) => string; + }) => string; + + interface CompileOptions extends ModuleCompileOptions { + /** + * Sets the name of the resulting JavaScript class (though the compiler will rename it if it would otherwise conflict with other variables in scope). + * If unspecified, will be inferred from `filename` + */ + name?: string; + /** + * If `true`, tells the compiler to generate a custom element constructor instead of a regular Svelte component. + * + * @default false + */ + customElement?: boolean; + /** + * If `true`, getters and setters will be created for the component's props. If `false`, they will only be created for readonly exported values (i.e. those declared with `const`, `class` and `function`). If compiling with `customElement: true` this option defaults to `true`. + * + * @default false + */ + accessors?: boolean; + /** + * The namespace of the element; e.g., `"html"`, `"svg"`, `"foreign"`. + * + * @default 'html' + */ + namespace?: Namespace; + /** + * If `true`, tells the compiler that you promise not to mutate any objects. + * This allows it to be less conservative about checking whether values have changed. + * + * @default false + */ + immutable?: boolean; + /** + * - `'injected'`: styles will be included in the JavaScript class and injected at runtime for the components actually rendered. + * - `'external'`: the CSS will be returned in the `css` field of the compilation result. Most Svelte bundler plugins will set this to `'external'` and use the CSS that is statically generated for better performance, as it will result in smaller JavaScript bundles and the output can be served as cacheable `.css` files. + * This is always `'injected'` when compiling with `customElement` mode. + */ + css?: 'injected' | 'external'; + /** + * A function that takes a `{ hash, css, name, filename }` argument and returns the string that is used as a classname for scoped CSS. + * It defaults to returning `svelte-${hash(css)}`. + * + * @default undefined + */ + cssHash?: CssHashGetter; + /** + * If `true`, your HTML comments will be preserved during server-side rendering. By default, they are stripped out. + * + * @default false + */ + preserveComments?: boolean; + /** + * If `true`, whitespace inside and between elements is kept as you typed it, rather than removed or collapsed to a single space where possible. + * + * @default false + */ + preserveWhitespace?: boolean; + /** + * Set to `true` to force the compiler into runes mode, even if there are no indications of runes usage. + * Set to `false` to force the compiler into ignoring runes, even if there are indications of runes usage. + * Set to `undefined` (the default) to infer runes mode from the component code. + * Is always `true` for JS/TS modules compiled with Svelte. + * Will be `true` by default in Svelte 6. + * @default undefined + */ + runes?: boolean | undefined; + /** + * If `true`, exposes the Svelte major version on the global `window` object in the browser. + * + * @default true + */ + discloseVersion?: boolean; + /** + * @deprecated Use these only as a temporary solution before migrating your code + */ + legacy?: { + /** + * Applies a transformation so that the default export of Svelte files can still be instantiated the same way as in Svelte 4 — + * as a class when compiling for the browser (as though using `createClassComponent(MyComponent, {...})` from `svelte/legacy`) + * or as an object with a `.render(...)` method when compiling for the server + * @default false + */ + componentApi?: boolean; + }; + /** + * An initial sourcemap that will be merged into the final output sourcemap. + * This is usually the preprocessor sourcemap. + * + * @default null + */ + sourcemap?: object | string; + /** + * Used for your JavaScript sourcemap. + * + * @default null + */ + outputFilename?: string; + /** + * Used for your CSS sourcemap. + * + * @default null + */ + cssOutputFilename?: string; + + // Other Svelte 4 compiler options: + // enableSourcemap?: EnableSourcemap; // TODO bring back? https://github.com/sveltejs/svelte/pull/6835 + // legacy?: boolean; // TODO compiler error noting the new purpose? + } + + interface ModuleCompileOptions { + /** + * If `true`, causes extra code to be added that will perform runtime checks and provide debugging information during development. + * + * @default false + */ + dev?: boolean; + /** + * If `"client"`, Svelte emits code designed to run in the browser. + * If `"server"`, Svelte emits code suitable for server-side rendering. + * If `false`, nothing is generated. Useful for tooling that is only interested in warnings. + * + * @default 'client' + */ + generate?: 'client' | 'server' | false; + /** + * Used for debugging hints and sourcemaps. Your bundler plugin will set it automatically. + */ + filename?: string; + } + + type DeclarationKind = + | 'var' + | 'let' + | 'const' + | 'function' + | 'import' + | 'param' + | 'rest_param' + | 'synthetic'; + + interface Binding { + node: Identifier; + /** + * - `normal`: A variable that is not in any way special + * - `prop`: A normal prop (possibly mutated) + * - `rest_prop`: A rest prop + * - `state`: A state variable + * - `derived`: A derived variable + * - `each`: An each block context variable + * - `store_sub`: A $store value + * - `legacy_reactive`: A `$:` declaration + * - `legacy_reactive_import`: An imported binding that is mutated inside the component + */ + kind: + | 'normal' + | 'prop' + | 'rest_prop' + | 'state' + | 'frozen_state' + | 'derived' + | 'each' + | 'store_sub' + | 'legacy_reactive' + | 'legacy_reactive_import'; + declaration_kind: DeclarationKind; + /** + * What the value was initialized with. + * For destructured props such as `let { foo = 'bar' } = $props()` this is `'bar'` and not `$props()` + */ + initial: null | Expression | FunctionDeclaration | ClassDeclaration | ImportDeclaration; + is_called: boolean; + references: { node: Identifier; path: SvelteNode[] }[]; + mutated: boolean; + reassigned: boolean; + scope: Scope; + /** For `legacy_reactive`: its reactive dependencies */ + legacy_dependencies: Binding[]; + /** Legacy props: the `class` in `{ export klass as class}` */ + prop_alias: string | null; + /** If this is set, all references should use this expression instead of the identifier name */ + expression: Expression | null; + /** If this is set, all mutations should use this expression */ + mutation: ((assignment: AssignmentExpression, context: Context) => Expression) | null; + } + interface BaseNode_1 { + type: string; + start: number; + end: number; + } + + interface BaseElement_1 extends BaseNode_1 { + name: string; + attributes: Array; + children: Array; + } + + interface LegacyAction extends BaseNode_1 { + type: 'Action'; + /** The 'x' in `use:x` */ + name: string; + /** The 'y' in `use:x={y}` */ + expression: null | Expression; + } + + interface LegacyAnimation extends BaseNode_1 { + type: 'Animation'; + /** The 'x' in `animate:x` */ + name: string; + /** The y in `animate:x={y}` */ + expression: null | Expression; + } + + interface LegacyBinding extends BaseNode_1 { + type: 'Binding'; + /** The 'x' in `bind:x` */ + name: string; + /** The y in `bind:x={y}` */ + expression: Identifier | MemberExpression; + } + + interface LegacyBody extends BaseElement_1 { + type: 'Body'; + name: 'svelte:body'; + } + + interface LegacyAttribute extends BaseNode_1 { + type: 'Attribute'; + name: string; + value: true | Array; + } + + interface LegacyAttributeShorthand extends BaseNode_1 { + type: 'AttributeShorthand'; + expression: Expression; + } + + interface LegacyLet extends BaseNode_1 { + type: 'Let'; + /** The 'x' in `let:x` */ + name: string; + /** The 'y' in `let:x={y}` */ + expression: null | Identifier | ArrayExpression | ObjectExpression; + } + + interface LegacyCatchBlock extends BaseNode_1 { + type: 'CatchBlock'; + children: LegacySvelteNode[]; + skip: boolean; + } + + interface LegacyClass extends BaseNode_1 { + type: 'Class'; + /** The 'x' in `class:x` */ + name: 'class'; + /** The 'y' in `class:x={y}`, or the `x` in `class:x` */ + expression: Expression; + } + + interface LegacyDocument extends BaseElement_1 { + type: 'Document'; + } + + interface LegacyElement { + type: 'Element'; + } + + interface LegacyEventHandler extends BaseNode_1 { + type: 'EventHandler'; + /** The 'x' in `on:x` */ + name: string; + /** The 'y' in `on:x={y}` */ + expression: null | Expression; + modifiers: string[]; + } + + interface LegacyHead extends BaseElement_1 { + type: 'Head'; + } + + interface LegacyInlineComponent extends BaseElement_1 { + type: 'InlineComponent'; + /** Set if this is a `` */ + expression?: Expression; + } + + interface LegacyMustacheTag extends BaseNode_1 { + type: 'MustacheTag'; + expression: Expression; + } + + interface LegacyOptions { + type: 'Options'; + name: 'svelte:options'; + attributes: Array; + } + + interface LegacyPendingBlock extends BaseNode_1 { + type: 'PendingBlock'; + children: LegacySvelteNode[]; + skip: boolean; + } + + interface LegacyRawMustacheTag extends BaseNode_1 { + type: 'RawMustacheTag'; + expression: Expression; + } + + interface LegacySpread extends BaseNode_1 { + type: 'Spread'; + expression: Expression; + } + + interface LegacySlot extends BaseElement_1 { + type: 'Slot'; + } + + interface LegacySlotTemplate extends BaseElement_1 { + type: 'SlotTemplate'; + } + + interface LegacyThenBlock extends BaseNode_1 { + type: 'ThenBlock'; + children: LegacySvelteNode[]; + skip: boolean; + } + + interface LegacyTitle extends BaseElement_1 { + type: 'Title'; + name: 'title'; + } + + interface LegacyConstTag extends BaseNode_1 { + type: 'ConstTag'; + expression: AssignmentExpression; + } + + interface LegacyTransition extends BaseNode_1 { + type: 'Transition'; + /** The 'x' in `transition:x` */ + name: string; + /** The 'y' in `transition:x={y}` */ + expression: null | Expression; + modifiers: Array<'local' | 'global'>; + /** True if this is a `transition:` or `in:` directive */ + intro: boolean; + /** True if this is a `transition:` or `out:` directive */ + outro: boolean; + } + + interface LegacyWindow extends BaseElement_1 { + type: 'Window'; + } + + type LegacyDirective = + | LegacyAnimation + | LegacyBinding + | LegacyClass + | LegacyLet + | LegacyEventHandler + | StyleDirective + | LegacyTransition + | LegacyAction; + + type LegacyAttributeLike = LegacyAttribute | LegacySpread | LegacyDirective; + + type LegacyElementLike = + | LegacyBody + | LegacyCatchBlock + | LegacyDocument + | LegacyElement + | LegacyHead + | LegacyInlineComponent + | LegacyMustacheTag + | LegacyOptions + | LegacyPendingBlock + | LegacyRawMustacheTag + | LegacySlot + | LegacySlotTemplate + | LegacyThenBlock + | LegacyTitle + | LegacyWindow; + + type LegacySvelteNode = + | LegacyConstTag + | LegacyElementLike + | LegacyAttributeLike + | LegacyAttributeShorthand + | Text; + /** + * The preprocess function provides convenient hooks for arbitrarily transforming component source code. + * For example, it can be used to convert a