carbon-design-system / sveld

Licence: Apache-2.0 license
Generate TypeScript definitions for your Svelte components

Programming Languages

Svelte
593 projects
typescript
32286 projects
javascript
184084 projects - #8 most used programming language
HTML
75241 projects

Projects that are alternatives of or similar to sveld

svelte-intersection-observer
Detect if an element is in the viewport using the Intersection Observer API
Stars: ✭ 151 (-46.26%)
Mutual labels:  svelte, typescript-definitions, svelte-component
svelte-search
Accessible, customizable Svelte search component
Stars: ✭ 17 (-93.95%)
Mutual labels:  svelte, svelte-component
svelte-lottie-player
Lottie Player component for Svelte
Stars: ✭ 90 (-67.97%)
Mutual labels:  svelte, svelte-component
docgen
The docs.json generator for discord.js and its related projects
Stars: ✭ 59 (-79%)
Mutual labels:  jsdoc, docgen
svelte-undoable
Memento design pattern in Svelte
Stars: ✭ 39 (-86.12%)
Mutual labels:  svelte, svelte-component
svelte-inview
A Svelte action that monitors an element enters or leaves the viewport.🔥
Stars: ✭ 358 (+27.4%)
Mutual labels:  svelte, svelte-component
kahi-ui
Straight-forward Svelte UI for the Web
Stars: ✭ 169 (-39.86%)
Mutual labels:  svelte, typescript-definitions
svelte-marquee-text
[CSS GPU Animation] Marquee Text for Svelte
Stars: ✭ 47 (-83.27%)
Mutual labels:  svelte, svelte-component
svelte-multiselect
Keyboard-friendly, accessible and highly customizable multi-select component
Stars: ✭ 91 (-67.62%)
Mutual labels:  svelte, svelte-component
carbon-components-svelte
Svelte implementation of the Carbon Design System
Stars: ✭ 1,615 (+474.73%)
Mutual labels:  svelte, typescript-definitions
svelte-stripe-js
Everything you need to add Stripe Elements to your Svelte project
Stars: ✭ 139 (-50.53%)
Mutual labels:  svelte
svelte-match-media
a matchMedia plugin for svelte 3
Stars: ✭ 38 (-86.48%)
Mutual labels:  svelte
felt-mockup
retired mockup 💚 customizable community tools that feel good
Stars: ✭ 47 (-83.27%)
Mutual labels:  svelte
mathesar
Web application providing an intuitive user experience to databases.
Stars: ✭ 95 (-66.19%)
Mutual labels:  svelte
website
Gitpod website and documentation
Stars: ✭ 233 (-17.08%)
Mutual labels:  svelte
svelte-bricks
Naive Svelte Masonry component without column balancing (ragged columns at the bottom)
Stars: ✭ 22 (-92.17%)
Mutual labels:  svelte
webgpu-seed
🔺🌱 An example on how to render a hello triangle with WebGPU.
Stars: ✭ 178 (-36.65%)
Mutual labels:  typescript-definitions
supabase-ui-svelte
Supabase authentication UI for Svelte
Stars: ✭ 83 (-70.46%)
Mutual labels:  svelte
templates
tsParticles website templates collection
Stars: ✭ 42 (-85.05%)
Mutual labels:  svelte
svelte-fullcalendar
A Svelte component wrapper around FullCalendar
Stars: ✭ 123 (-56.23%)
Mutual labels:  svelte

sveld

NPM GitHub npm downloads to date

sveld generates TypeScript definitions for Svelte components by statically analyzing their props, events, slots and more. Prop types and signatures can be defined using JSDoc notation. This documentation generator can also emit component documentation in Markdown and JSON output formats.

The purpose of this project is to make third party Svelte component libraries compatible with the Svelte Language Server and TypeScript with minimal effort required by the author. For example, TypeScript definitions may be used during development via intelligent code completion in Integrated Development Environments (IDE) like VSCode.

Carbon Components Svelte uses this library to auto-generate component types and API metadata:

Please note that the generated TypeScript definitions require Svelte version 3.31 or greater.


Given a Svelte component, sveld can infer basic prop types to generate TypeScript definitions compatible with the Svelte Language Server:

Button.svelte

<script>
  export let type = "button";
  export let primary = false;
</script>

<button {...$$restProps} {type} class:primary on:click>
  <slot>Click me</slot>
</button>

The generated definition extends the official SvelteComponentTyped interface exported from Svelte.

Button.svelte.d.ts

/// <reference types="svelte" />
import { SvelteComponentTyped } from "svelte";

export interface ButtonProps extends svelte.JSX.HTMLAttributes<HTMLElementTagNameMap["button"]> {
  /**
   * @default "button"
   */
  type?: string;

  /**
   * @default false
   */
  primary?: boolean;
}

export default class Button extends SvelteComponentTyped<
  ButtonProps,
  { click: WindowEventMap["click"] },
  { default: {} }
> {}

Sometimes, inferring prop types is insufficient.

Prop/event/slot types and signatures can be augmented using JSDoc notations.

/** @type {"button" | "submit" | "reset"} */
export let type = "button";

/**
 * Set to `true` to use the primary variant
 */
export let primary = false;

The accompanying JSDoc annotations would generate the following:

/// <reference types="svelte" />
import { SvelteComponentTyped } from "svelte";

export interface ButtonProps extends svelte.JSX.HTMLAttributes<HTMLElementTagNameMap["button"]> {
  /**
   * @default "button"
   */
  type?: "button" | "submit" | "reset";

  /**
   * Set to `true` to use the primary variant
   * @default false
   */
  primary?: boolean;
}

export default class Button extends SvelteComponentTyped<
  ButtonProps,
  { click: WindowEventMap["click"] },
  { default: {} }
> {}

Table of Contents

Approach

sveld uses the Svelte compiler to statically analyze Svelte components exported from a library to generate documentation useful to the end user.

Extracted metadata include:

  • props
  • slots
  • forwarded events
  • dispatched events
  • $$restProps

This library adopts a progressively enhanced approach. Any property type that cannot be inferred (e.g., "hello" is a string) falls back to "any" to minimize incorrectly typed properties or signatures. To mitigate this, the library author can add JSDoc annotations to specify types that cannot be reliably inferred. This represents a progressively enhanced approach because JSDocs are comments that can be ignored by the compiler.

The generated TypeScript definitions for a component extends the SvelteComponentTyped interface available in svelte version 3.31.

Usage

Installation

Install sveld as a development dependency.

yarn add -D sveld
# OR
npm i -D sveld
# OR
pnpm i -D sveld

Rollup

Import and add sveld as a plugin to your rollup.config.js.

// rollup.config.js
import svelte from "rollup-plugin-svelte";
import resolve from "@rollup/plugin-node-resolve";
import sveld from "sveld";

export default {
  input: "src/index.js",
  output: {
    format: "es",
    file: "lib/index.mjs",
  },
  plugins: [svelte(), resolve(), sveld()],
};

When building the library, TypeScript definitions are emitted to the types folder by default.

Customize the output folder using the typesOptions.outDir option.

The following example emits the output to the dist folder:

sveld({
+  typesOptions: {
+    outDir: 'dist'
+  }
})

The integration folder contains example set-ups:

CLI

The CLI wraps the Rollup plugin and uses the "svelte" field defined in your package.json as the entry point.

npx sveld

Append --json or --markdown flags to generate documentation in JSON/Markdown formats, respectively.

npx sveld --json --markdown

Node.js

You can also use sveld programmatically in Node.js.

If no input is specified, sveld will infer the entry point based on the package.json#svelte field.

const { sveld } = require("sveld");
const pkg = require("./package.json");

sveld({
  input: "./src/index.js",
  glob: true,
  markdown: true,
  markdownOptions: {
    onAppend: (type, document, components) => {
      if (type === "h1")
        document.append("quote", `${components.size} components exported from ${pkg.name}@${pkg.version}.`);
    },
  },
  json: true,
  jsonOptions: {
    outFile: "docs/src/COMPONENT_API.json",
  },
});

jsonOptions.outDir

If json is true, a COMPONENT_API.json file will be generated at the root of your project. This file contains documentation for all components.

Use the jsonOptions.outDir option to specify the folder for individual JSON files to be emitted.

sveld({
  json: true,
  jsonOptions: {
    // an individual JSON file will be generated for each component API
    // e.g. "docs/Button.api.json"
    outDir: "docs",
  },
});

Publishing to NPM

TypeScript definitions are outputted to the types folder by default. Don't forget to include the folder in your package.json when publishing the package to NPM.

{
  "svelte": "./src/index.js",
  "main": "./lib/index.mjs",
+ "types": "./types/index.d.ts",
  "files": [
    "src",
    "lib",
+   "types",
  ]
}

Available Options

By default, only TypeScript definitions are generated.

To generate documentation in Markdown and JSON formats, set markdown and json to true.

sveld({
+  markdown: true,
+  json: true,
})

API Reference

@type

Without a @type annotation, sveld will infer the primitive type for a prop:

export let kind = "primary";
// inferred type: "string"

Use the @type tag to explicitly document the type. In the following example, the kind property has an enumerated (enum) type.

Signature:

/**
 * Optional description
 * @type {Type}
 */

Example:

/**
 * Specify the kind of button
 * @type {"primary" | "secondary" | "tertiary"}
 */
export let kind = "primary";

/**
 * Specify the Carbon icon to render
 * @type {typeof import("carbon-icons-svelte").CarbonIcon}
 */
export let renderIcon = Close20;

@typedef

The @typedef tag can be used to define a common type that is used multiple times within a component. All typedefs defined in a component will be exported from the generated TypeScript definition file.

Signature:

/**
 * @typedef {Type} TypeName
 */

Example:

/**
 * @typedef {string} AuthorName
 * @typedef {{ name?: AuthorName; dob?: string; }} Author
 */

/** @type {Author} */
export let author = {};

/** @type {Author[]} */
export let authors = [];

@slot

Use the @slot tag for typing component slots. Note that @slot is a non-standard JSDoc tag.

Signature:

/**
 * @slot {Type} [slot name]
 */

Example:

<script>
  /**
   * @slot {{ prop: number; doubled: number; }}
   * @slot {{ props: { class?: string; } }} description
   */

  export let prop = 0;
</script>

<h1>
  <slot {prop} doubled={prop * 2} />
</h1>

<p>
  <slot name="description" props={{ class: $$props.class }} />
</p>

@event

Use the @event tag for typing dispatched events. An event name must be specified.

Signature:

/**
 * @event {EventDetail} eventname
 */

Example:

/**
 * @event {{ key: string }} button:key
 */

export let key = "";

import { createEventDispatcher } from "svelte";

const dispatch = createEventDispatcher();

$: dispatch("button:key", { key });

@restProps

sveld can pick up inline HTML elements that $$restProps is forwarded to. However, it cannot infer the underlying element for instantiated components.

You can use the @restProps tag to specify the element tags that $$restProps is forwarded to.

Signature:

/**
 * Single element
 * @restProps {tagname}
 *
 * Multiple elements
 * @restProps {tagname-1 | tagname-2 | tagname-3}
 */

Example:

<script>
  /** @restProps {h1 | button} */
  export let edit = false;

  import Button from "../";
</script>

{#if edit}
  <Button {...$$restProps} />
{:else}
  <h1 {...$$restProps}><slot /></h1>
{/if}

@extends

In some cases, a component may be based on another component. The @extends tag can be used to extend generated component props.

Signature:

/**
 * @extends {<relative path to component>} ComponentProps
 */

Example:

/** @extends {"./Button.svelte"} ButtonProps */

export const secondary = true;

import Button from "./Button.svelte";

@component comments

The Svelte Language Server supports component-level comments through the following syntax: <!-- @component [comment] -->.

sveld will copy these over to the exported default component in the TypeScript definition.

Example:

<!-- @component
@example
<Button>
  Text
</Button>
-->
<button>
  <slot />
</button>

Output:

/**
 * @example
 * <Button>
 *   Text
 * </Button>
 */
export default class Button extends SvelteComponentTyped<ButtonProps, {}, { default: {} }> {}

Contributing

Refer to the contributing guidelines.

License

Apache-2.0

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].