An open API service indexing awesome lists of open source software.

https://github.com/carbon-design-system/sveld

Generate TypeScript definitions for your Svelte components
https://github.com/carbon-design-system/sveld

docgen documentation jsdoc svelte svelte-component typescript-definitions

Last synced: 21 days ago
JSON representation

Generate TypeScript definitions for your Svelte components

Awesome Lists containing this project

README

          

# sveld

[![NPM][npm]][npm-url]
![GitHub](https://img.shields.io/github/license/carbon-design-system/sveld?color=262626&style=for-the-badge)
![npm downloads to date](https://img.shields.io/npm/dt/sveld?color=262626&style=for-the-badge)

`sveld` is a TypeScript definition generator for Svelte components. It analyzes props, events, slots, and other component features through static analysis. Types and signatures can be defined using [JSDoc notation](https://jsdoc.app/). The tool can also generate component documentation in Markdown and JSON 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](https://github.com/carbon-design-system/carbon-components-svelte) uses this library to auto-generate component types and API metadata.

**Note:** `sveld` supports Svelte 3, 4, and 5, but does not support Svelte 5-specific syntax or runes-only usage. Components must use traditional Svelte syntax (e.g., `export let` for props, not `$props()`).

---

Given a Svelte component, `sveld` can infer basic prop types to generate TypeScript definitions compatible with the [Svelte Language Server](https://github.com/sveltejs/language-tools):

**Button.svelte**

```svelte

export let type = "button";
export let primary = false;

Click me

```

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

**Button.svelte.d.ts**

```ts
import { SvelteComponentTyped } from "svelte";
import type { SvelteHTMLElements } from "svelte/elements";

type $RestProps = SvelteHTMLElements["button"];

type $Props = {
/**
* @default "button"
*/
type?: string;

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

[key: `data-${string}`]: any;
};

export type ButtonProps = Omit<$RestProps, keyof $Props> & $Props;

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

Sometimes, inferring prop types is insufficient.

Prop/event/slot types and signatures can be augmented using [JSDoc](https://jsdoc.app/) notations.

```js
/** @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:

```ts
import type { SvelteHTMLElements } from "svelte/elements";

type $RestProps = SvelteHTMLElements["button"];

type $Props = {
/**
* @default "button"
*/
type?: "button" | "submit" | "reset";

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

export type ButtonProps = Omit<$RestProps, keyof $Props> & $Props;

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

---

## Table of Contents

- [Approach](#approach)
- [Usage](#usage)
- [Installation](#installation)
- [Vite](#vite)
- [Node.js](#nodejs)
- [CLI](#cli)
- [Publishing to NPM](#publishing-to-npm)
- [Available Options](#available-options)
- [API Reference](#api-reference)
- [@type](#type)
- [@typedef](#typedef)
- [@slot](#slot)
- [Svelte 5 Snippet Compatibility](#svelte-5-snippet-compatibility)
- [@event](#event)
- [Context API](#context-api)
- [@restProps](#restprops)
- [@extendProps](#extendprops)
- [@generics](#generics)
- [@component comments](#component-comments)
- [Accessor Props](#accessor-props)
- [Contributing](#contributing)
- [License](#license)

## 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
- context (setContext/getContext)
- `$$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.

## Usage

### Installation

Install `sveld` as a development dependency.

```sh
# npm
npm i -D sveld

# pnpm
pnpm i -D sveld

# Bun
bun i -D sveld

# Yarn
yarn add -D sveld
```

### Vite

Import and add `sveld` as a plugin to your `vite.config.ts`. The plugin only runs during `vite build` (not the dev server).

```ts
// vite.config.ts
import { svelte } from "@sveltejs/vite-plugin-svelte";
import sveld from "sveld";
import { defineConfig } from "vite";

export default defineConfig({
plugins: [svelte(), sveld()],
});
```

Since Vite uses Rollup for production builds, `sveld` also works in Rollup configurations.

By default, `sveld` will use the `"svelte"` field from your `package.json` to determine the entry point. You can override this by specifying an explicit `entry` option:

```js
sveld({
entry: "src/index.js",
});
```

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:

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

### CLI

The CLI uses the `"svelte"` field from your `package.json` as the entry point:

```sh
npx sveld
```

Generate documentation in JSON and/or Markdown formats using the following flags:

```sh
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.

```js
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.

```js
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.

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

## Available Options

### Plugin Options

- **`entry`** (string, optional): Specify the entry point to uncompiled Svelte source. If not provided, sveld will use the `"svelte"` field from `package.json`.
- **`glob`** (boolean, optional): Enable glob mode to analyze all `*.svelte` files.
- **`types`** (boolean, optional, default: `true`): Generate TypeScript definitions.
- **`typesOptions`** (object, optional): Options for TypeScript definition generation.
- **`json`** (boolean, optional): Generate component documentation in JSON format.
- **`jsonOptions`** (object, optional): Options for JSON output.
- **`markdown`** (boolean, optional): Generate component documentation in Markdown format.
- **`markdownOptions`** (object, optional): Options for Markdown output.

By default, only TypeScript definitions are generated.

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

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

## API Reference

### `@type`

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

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

For template literal default values, `sveld` infers the type as `string`:

```js
export let id = `ccs-${Math.random().toString(36)}`;
// 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:

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

Example:

```js
/**
* 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:

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

Example:

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

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

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

#### Using `@property` for complex typedefs

For complex object types, use the `@property` tag to document individual properties. This provides better documentation and IDE support with per-property tooltips.

Signature:

```js
/**
* Type description
* @typedef {object} TypeName
* @property {Type} propertyName - Property description
*/
```

Example:

```js
/**
* Represents a user in the system
* @typedef {object} User
* @property {string} name - The user's full name
* @property {string} email - The user's email address
* @property {number} age - The user's age in years
*/

/** @type {User} */
export let user = { name: "John", email: "john@example.com", age: 30 };
```

Output:

```ts
export type User = {
/** The user's full name */
name: string;
/** The user's email address */
email: string;
/** The user's age in years */
age: number;
};

export type ComponentProps = {
/**
* Represents a user in the system
* @default { name: "John", email: "john@example.com", age: 30 }
*/
user?: User;
};
```

#### Optional properties and default values

Following JSDoc standards, use square brackets to mark properties as optional. You can also specify default values using the `[propertyName=defaultValue]` syntax.

Signature:

```js
/**
* @typedef {object} TypeName
* @property {Type} [optionalProperty] - Optional property description
* @property {Type} [propertyWithDefault=defaultValue] - Property with default value
*/
```

Example:

```js
/**
* Configuration options for the component
* @typedef {object} ComponentConfig
* @property {boolean} enabled - Whether the component is enabled
* @property {string} theme - The component theme
* @property {number} [timeout=5000] - Optional timeout in milliseconds
* @property {boolean} [debug] - Optional debug mode flag
*/

/** @type {ComponentConfig} */
export let config = { enabled: true, theme: "dark" };
```

Output:

```ts
export type ComponentConfig = {
/** Whether the component is enabled */
enabled: boolean;
/** The component theme */
theme: string;
/** Optional timeout in milliseconds @default 5000 */
timeout?: number;
/** Optional debug mode flag */
debug?: boolean;
};

export type ComponentProps = {
/**
* Configuration options for the component
* @default { enabled: true, theme: "dark" }
*/
config?: ComponentConfig;
};
```

> **Note:** The inline syntax `@typedef {{ name: string }} User` continues to work for backwards compatibility.

### `@slot`

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

Descriptions are optional for named slots. Currently, the default slot cannot have a description.

Signature:

```js
/**
* @slot {Type} slot-name [slot description]
*/

Omit the `slot-name` to type the default slot.

/**
* @slot {Type}
*/
```

Example:

```svelte

/**
* @slot {{ prop: number; doubled: number; }}
* @slot {{}} title
* @slot {{ prop: number }} body - Customize the paragraph text.
*/

export let prop = 0;







```

#### Svelte 5 Snippet Compatibility

For Svelte 5 compatibility, `sveld` automatically generates optional snippet props for all slots. This allows consumers to use either the traditional slot syntax or Svelte 5's `{#snippet}` syntax.

For slots with props (e.g., `let:prop`), the generated type uses a Snippet-compatible signature:

```ts
slotName?: (this: void, ...args: [{ prop: PropType }]) => void;
```

For slots without props:

```ts
slotName?: (this: void) => void;
```

**Why this signature?**

- **`this: void`** – Ensures the snippet cannot be called with a `this` context, matching Svelte's internal enforcement that snippets are pure render functions
- **`...args: [Props]`** – Uses tuple spread for type-safe parameters. This accepts fixed-length tuples (like `[{ row: Row }]`) while rejecting array types (like `Props[]`), matching how Svelte's `Snippet` type works

**Default slot (`children` prop):**

The default slot generates an optional `children` snippet prop:

```svelte

{#snippet children({ item, index })}
{item.text} (#{index})
{/snippet}

```

Generated types:

```ts
type DropdownProps = {
items: Item[];
selectedId?: string;

// Default slot as children snippet prop
children?: (this: void, ...args: [{ item: Item; index: number }]) => void;
};
```

**Named slots:**

```svelte

{#snippet cell({ cell, row })}
{#if cell.key === 'actions'}
handleAction(row)}>Edit
{:else}
{cell.value}
{/if}
{/snippet}

```

The generated TypeScript definition includes both the snippet prop and the traditional slot definition:

```ts
type DataTableProps = {
// ... other props

// Snippet prop for Svelte 5 compatibility
cell?: (
this: void,
...args: [
{
row: Row;
cell: DataTableCell;
rowIndex: number;
cellIndex: number;
},
]
) => void;

// Default slot as children prop
children?: (this: void) => void;
};

export default class DataTable extends SvelteComponentTyped<
DataTableProps,
{
/* events */
},
{
// Traditional slot definition (Svelte 3/4)
default: Record;
cell: {
row: Row;
cell: DataTableCell;
rowIndex: number;
cellIndex: number;
};
}
> {}
```

### `@event`

Use the `@event` tag to type dispatched events. An event name is required and a description optional.

Use `null` as the value if no event detail is provided.

Signature:

```js
/**
* Optional event description
* @event {EventDetail} eventname [inline description]
*/
```

Example:

```js
/**
* @event {{ key: string }} button:key
* @event {null} key – Fired when `key` changes.
*/

export let key = "";

import { createEventDispatcher } from "svelte";

const dispatch = createEventDispatcher();

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

Output:

```ts
export default class Component extends SvelteComponentTyped<
ComponentProps,
{
"button:key": CustomEvent<{ key: string }>;
/** Fired when `key` changes. */ key: CustomEvent;
},
Record
> {}
```

#### Using `@property` for complex event details

For events with complex object payloads, use the `@property` tag to document individual properties. The main comment description will be used as the event description.

Signature:

```js
/**
* Event description
* @event eventname
* @type {object}
* @property {Type} propertyName - Property description
*/
```

Example:

```js
/**
* Fired when the user submits the form
*
* @event submit
* @type {object}
* @property {string} name - The user's name
* @property {string} email - The user's email address
* @property {boolean} newsletter - Whether the user opted into the newsletter
*/

import { createEventDispatcher } from "svelte";

const dispatch = createEventDispatcher();

function handleSubmit() {
dispatch("submit", {
name: "Jane Doe",
email: "jane@example.com",
newsletter: true,
});
}
```

Output:

```ts
export default class Component extends SvelteComponentTyped<
ComponentProps,
{
/** Fired when the user submits the form */
submit: CustomEvent<{
/** The user's name */
name: string;
/** The user's email address */
email: string;
/** Whether the user opted into the newsletter */
newsletter: boolean;
}>;
},
Record
> {}
```

#### Optional properties in event details

Just like with typedefs, you can mark event detail properties as optional using square brackets. This is useful when some properties may not always be included in the event payload.

Example:

```js
/**
* Snowball event fired when throwing a snowball
*
* @event snowball
* @type {object}
* @property {boolean} isPacked - Indicates whether the snowball is tightly packed
* @property {number} speed - The speed of the snowball in mph
* @property {string} [color] - Optional color of the snowball
* @property {number} [density=0.9] - Optional density with default value
*/

import { createEventDispatcher } from "svelte";

const dispatch = createEventDispatcher();

function throwSnowball() {
dispatch("snowball", {
isPacked: true,
speed: 50,
});
}
```

Output:

```ts
export default class Component extends SvelteComponentTyped<
ComponentProps,
{
/** Snowball event fired when throwing a snowball */
snowball: CustomEvent<{
/** Indicates whether the snowball is tightly packed */
isPacked: boolean;
/** The speed of the snowball in mph */
speed: number;
/** Optional color of the snowball */
color?: string;
/** Optional density with default value @default 0.9 */
density?: number;
}>;
},
Record
> {}
```

### Context API

`sveld` automatically generates TypeScript definitions for Svelte's `setContext`/`getContext` API by extracting types from JSDoc annotations on the context values.

#### How it works

When you use `setContext` in a component, `sveld` will:

1. Detect the `setContext` call
2. Extract the context key (must be a string literal)
3. Find JSDoc `@type` annotations on the variables being passed
4. Generate a TypeScript type export for the context

#### Example

**Modal.svelte**

```svelte

import { setContext } from 'svelte';

/**
* Close the modal
* @type {() => void}
*/
const close = () => {
// Close logic
};

/**
* Open the modal with content
* @type {(component: any, props?: any) => void}
*/
const open = (component, props) => {
// Open logic
};

setContext('simple-modal', { open, close });


```

**Generated TypeScript definition:**

```ts
export type SimpleModalContext = {
/** Open the modal with content */
open: (component: any, props?: any) => void;
/** Close the modal */
close: () => void;
};

export type ModalProps = {};

export default class Modal extends SvelteComponentTyped<
ModalProps,
Record,
{ default: Record }
> {}
```

**Consumer usage:**

```svelte

import { getContext } from 'svelte';
import type { SimpleModalContext } from 'modal-library/Modal.svelte';

// Fully typed with autocomplete!
const { close, open } = getContext<SimpleModalContext>('simple-modal');

Close
```

#### Explicitly typing contexts

There are several ways to provide type information for contexts:

**Option 1: Inline JSDoc on variables (recommended)**

```svelte

import { setContext } from 'svelte';

/**
* @type {() => void}
*/
const close = () => {};

setContext('modal', { close });

```

**Option 2: Using @typedef for complex types**

```svelte

import { setContext } from 'svelte';

/**
* @typedef {object} TabData
* @property {string} id
* @property {string} label
* @property {boolean} [disabled]
*/

/**
* @type {(tab: TabData) => void}
*/
const addTab = (tab) => {};

setContext('tabs', { addTab });

```

**Option 3: Referencing imported types**

```svelte

import { setContext } from 'svelte';

/**
* @type {typeof import("./types").ModalAPI}
*/
const modalAPI = {
open: () => {},
close: () => {}
};

setContext('modal', modalAPI);

```

**Option 4: Direct object literal with inline functions**

```svelte

import { setContext } from 'svelte';

// sveld infers basic function signatures
setContext('modal', {
open: (component, props) => {}, // Inferred as (arg, arg) => any
close: () => {} // Inferred as () => any
});

```

> **Note:** For best results, use explicit JSDoc `@type` annotations. Inline functions without annotations will be inferred with generic signatures.

#### Notes

- Context keys must be string literals (dynamic keys are not supported)
- Variables passed to `setContext` should have JSDoc `@type` annotations for accurate types
- The generated type name follows the pattern: `{PascalCase}Context`. Separators (hyphens, underscores, dots, colons, slashes, spaces) are stripped and each segment is capitalized:
| Context Key | Generated Type Name |
| --- | --- |
| `"simple-modal"` | `SimpleModalContext` |
| `"user_settings"` | `UserSettingsContext` |
| `"Carbon.Modal"` | `CarbonModalContext` |
| `"Carbon:Modal"` | `CarbonModalContext` |
| `"app/modal"` | `AppModalContext` |
| `"My Context"` | `MyContextContext` |
| `"Tabs"` | `TabsContext` |
- If no type annotation is found, the type defaults to `any` with a warning

### `@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:

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

Example:

```svelte

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

import Button from "../";

{#if edit}

{:else}


{/if}
```

### `@extendProps`

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

> **Note:** `@extends` is supported as an alias but `@extendProps` is preferred to avoid conflicts with standard JSDoc `@extends` (used for class inheritance).

Signature:

```js
/**
* @extendProps {} ComponentProps
*/
```

Example:

```js
/** @extendProps {"./Button.svelte"} ButtonProps */

export const secondary = true;

import Button from "./Button.svelte";
```

### `@generics`

Currently, to define generics for a Svelte component, you must use [`generics` attribute](https://github.com/dummdidumm/rfcs/blob/bfb14dc56a70ec6ddafebf2242b8e1500e06a032/text/ts-typing-props-slots-events.md#generics) on the script tag. Note that this feature is [experimental](https://svelte.dev/docs/typescript#experimental-advanced-typings) and may change in the future.

However, the `generics` attribute only works if using `lang="ts"`; the language server will produce an error if `generics` is used without specifying `lang="ts"`.

```svelte

```

Because `sveld` is designed to support JavaScript-only usage as a baseline, the API design to specify generics uses a custom JSDoc tag `@generics`.

Signature:

```js
/**
* @generics {GenericParameter} GenericName
*/
```

Example

```js
/**
* @generics {Row extends DataTableRow = any} Row
*/
```

The generated TypeScript definition will resemble the following:

```ts
// Props type includes the full constraint, enabling indexed access types like Row["id"]
export type ComponentProps = {
rows?: ReadonlyArray;
};

export default class Component<
Row extends DataTableRow = any,
> extends SvelteComponentTyped<
ComponentProps,
Record,
Record
> {}
```

For a parameter list, the name should be comma-separated but not include spaces.

```js
/**
* @generics {Param1, Param2} Name1,Name2
*/
```

```ts
export type ComponentProps = { ... };

export default class Component extends SvelteComponentTyped<
ComponentProps,
Record,
Record
> {}
```

### `@component` comments

The Svelte Language Server supports component-level comments through the following syntax: ``.

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

Example:

```svelte

```

Output:

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

### Accessor Props

Exported functions and consts become accessor props in generated TypeScript definitions. Use `@type` to document function signatures, or use `@param` and `@returns` (or `@return`) JSDoc tags for richer documentation.

Note that `@type` tag annotations take precedence over `@param`/`@returns` tags.

Signature:

```js
/**
* Function description
* @param {Type} paramName - Parameter description
* @param {Type} [optionalParam] - Optional parameter
* @returns {ReturnType} Return value description
*/
```

Example:

```svelte

/**
* @typedef {object} NotificationData
* @property {string} [id] - Optional id for deduplication
* @property {"error" | "info" | "success"} [kind]
*/

/**
* Add a notification to the queue.
* @param {NotificationData} notification
* @returns {string} The notification id
*/
export function add(notification) {
const id = notification.id ?? "id";
return id;
}

/**
* Remove a notification by id.
* @param {string} id
* @returns {boolean} True if the notification was found and removed
*/
export function remove(id) {
return true;
}

/**
* Get notification count.
* @returns {number} The number of notifications
*/
export function getCount() {
return 0;
}

```

Output:

```ts
export type NotificationData = {
/** Optional id for deduplication */
id?: string;
kind?: "error" | "info" | "success";
};

export type ComponentProps = Record;

export default class Component extends SvelteComponentTyped<
ComponentProps,
Record,
Record
> {
/**
* Add a notification to the queue.
*/
add: (notification: NotificationData) => string;

/**
* Remove a notification by id.
*/
remove: (id: string) => boolean;

/**
* Get notification count.
*/
getCount: () => number;
}
```

When only `@param` tags are present without `@returns`, the return type defaults to `any`. When only `@returns` is present without `@param`, the function signature is `() => returnType`.

## Contributing

Refer to the [contributing guidelines](CONTRIBUTING.md).

## License

[Apache-2.0](LICENSE)

[npm]: https://img.shields.io/npm/v/sveld.svg?color=262626&style=for-the-badge
[npm-url]: https://npmjs.com/package/sveld