npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

svelte-qa-ids

v1.0.2

Published

Automatically inject stable data-qa-id attributes into Svelte components for testing and automation

Readme

svelte-qa-ids

Automatically inject stable data-qa-id attributes into Svelte components for testing and automation

Features

  • Automated Injection: Scans Svelte files and programmatically inserts data-qa-id attributes
  • Stable IDs: Generates consistent, human-readable IDs based on component structure
  • Idempotent: Removes old IDs before adding new ones for clean updates
  • Svelte 5 Compatible: Uses svelte.preprocess for proper Svelte 5 syntax parsing
  • Smart Exclusion: Skips icon libraries (e.g., lucide-svelte) and handles parsing errors gracefully
  • CLI & API: Use as a command-line tool or programmatically in your build process

Installation

npm install -D svelte-qa-ids
# or
bun add -D svelte-qa-ids

CLI Usage

# Process all Svelte files in a directory
svelte-qa-ids src/

# Dry run to see what would change
svelte-qa-ids src/ --dry-run

# Process a single file
svelte-qa-ids src/routes/+page.svelte

# Verbose output
svelte-qa-ids src/ --verbose

# Custom component prefix length (2-10 characters)
svelte-qa-ids src/ --component 4
svelte-qa-ids src/ -c 2

Programmatic Usage

Effect-based API (Primary)

The library is built with Effect-ts for type-safe error handling and composability:

import { inject } from 'svelte-qa-ids';
import { Effect } from 'effect';

// Process a directory
const program = inject('src/', {
  verbose: true,
  prefixLength: 4,
});

// Run the Effect
const results = await Effect.runPromise(program);

// Handle errors with Effect
const safeProgram = inject('src/', {
  prefixLength: 4,
}).pipe(
  Effect.catchAll((error) =>
    Effect.succeed([
      {
        file: 'src/',
        success: false,
        error: error.message,
      },
    ])
  )
);

const results = await Effect.runPromise(safeProgram);

Promise-based API (Convenience)

For simpler use cases, a Promise-based wrapper is provided:

import { injectPromise } from 'svelte-qa-ids';

// Process a directory
const results = await injectPromise('src/', {
  verbose: true,
});

// Process a single file
await injectPromise('src/routes/+page.svelte');

// With custom options
await injectPromise('src/', {
  dryRun: true,
  prefixLength: 4,
  abbreviations: {
    'custom-button': 'cb',
  },
  skipComponents: ['MyIcon', 'AnotherIcon'],
});

data-qa-id Generation Rules

Component Prefix

The component prefix is generated from the file path and can be customized with the prefixLength option (default: 3, range: 2-10).

For pages (src/routes/...):

  • Uses first prefixLength letters of the route directory
  • Example with default (prefixLength=3): src/routes/analytics/+page.svelteana
  • Example with prefixLength=2: src/routes/analytics/+page.sveltean
  • Example with prefixLength=4: src/routes/analytics/+page.svelteanal
  • Root page (src/routes/+page.svelte) → rt

For components (src/lib/...):

  • Uses first prefixLength letters of each word in filename
  • Example with default (prefixLength=3): upgrade-banner.svelteupg-ban
  • Example with prefixLength=2: upgrade-banner.svelteup-ba
  • Example with prefixLength=4: question-counter.sveltequest-count

Tag Abbreviations

Common tags are abbreviated for conciseness:

| Tag | Abbreviation | |-----|--------------| | div | d | | button | btn | | input | in | | label | lbl | | span | sp | | section | sec | | form | f |

Examples

<!-- Before: src/routes/splash/+page.svelte -->
<div class="container">
  <h1>Welcome</h1>
  <button>Continue</button>
</div>

<!-- After (default prefixLength=3) -->
<div class="container" data-qa-id="spl-d">
  <h1 data-qa-id="spl-d-h1">Welcome</h1>
  <button data-qa-id="spl-d-btn">Continue</button>
</div>

<!-- After (prefixLength=2) -->
<div class="container" data-qa-id="sp-d">
  <h1 data-qa-id="sp-d-h1">Welcome</h1>
  <button data-qa-id="sp-d-btn">Continue</button>
</div>

<!-- After (prefixLength=4) -->
<div class="container" data-qa-id="spla-d">
  <h1 data-qa-id="spla-d-h1">Welcome</h1>
  <button data-qa-id="spla-d-btn">Continue</button>
</div>

Component example (src/lib/question-counter.svelte):

<!-- Before -->
<div class="counter">
  <button id="increment">+</button>
  <span>0</span>
</div>

<!-- After (default prefixLength=3) -->
<div class="counter" data-qa-id="que-d">
  <button id="increment" data-qa-id="que-d-btn">+</button>
  <span data-qa-id="que-d-sp">0</span>
</div>

<!-- After (prefixLength=4) -->
<div class="counter" data-qa-id="quest-d">
  <button id="increment" data-qa-id="quest-d-btn">+</button>
  <span data-qa-id="quest-d-sp">0</span>
</div>

Integration with Build Process

SvelteKit

Add to your package.json:

{
  "scripts": {
    "prebuild": "svelte-qa-ids src/"
  }
}

Vite

// vite.config.ts
import { inject } from 'svelte-qa-ids';

export default {
  plugins: [
    {
      name: 'inject-qa-ids',
      async buildStart() {
        await inject('src/');
      }
    }
  ]
};

Configuration Examples

Custom Prefix Length

Control how many characters from the component name are used for the ID prefix:

import { inject } from 'svelte-qa-ids';

// Use 2-character prefixes (more concise)
await inject('src/', { prefixLength: 2 });
// question-counter.svelte → qu-btn

// Use 4-character prefixes (more descriptive)
await inject('src/', { prefixLength: 4 });
// question-counter.svelte → quest-btn

// Default is 3 characters
await inject('src/');
// question-counter.svelte → que-btn

CLI Prefix Length

# Short prefix (2 chars)
svelte-qa-ids src/ --component 2

# Long prefix (5 chars)
svelte-qa-ids src/ --component 5

Custom Abbreviations

Override default tag abbreviations:

await inject('src/', {
  abbreviations: {
    'custom-button': 'cb',
    'data-table': 'dt',
    'user-card': 'uc',
  },
});

Skip Specific Components

Exclude certain components from processing:

await inject('src/', {
  skipComponents: ['Icon', 'MyIcon', 'ThirdPartyIcon'],
});

API Reference

inject(path, options?)

Injects data-qa-id attributes into Svelte files. This is the primary Effect-based API.

Parameters:

  • path (string) - Path to a file or directory
  • options (Options, optional) - Configuration options

Returns: Effect<Result[], Error>

Use Effect.runPromise() to execute:

import { inject } from 'svelte-qa-ids';
import { Effect } from 'effect';

const results = await Effect.runPromise(inject('src/'));

injectPromise(path, options?)

Promise-based convenience wrapper for inject().

Parameters:

  • path (string) - Path to a file or directory
  • options (Options, optional) - Configuration options

Returns: Promise<Result[]>

Options:

| Option | Type | Default | Description | |--------|------|---------|-------------| | abbreviations | Record<string, string> | built-in | Custom tag abbreviations | | prefixLength | number | 3 | Characters from component name for prefix (2-10) | | prefixGenerator | (filePath: string, prefixLength?: number) => string | built-in | Custom prefix function | | skipComponents | Set<string> \| string[] | lucide-svelte | Components to skip | | include | string[] | undefined | Include files matching glob patterns | | exclude | string[] | [] | Exclude files matching glob patterns | | dryRun | boolean | false | Don't modify files | | verbose | boolean | false | Detailed logging | | preserveOnError | boolean | true | Keep original content on parse errors |

Result:

interface Result {
  file: string;
  success: boolean;
  error?: string;
  injectedCount?: number;
  skipped?: boolean;
}

Known Limitations

Svelte 5 {#let} Blocks

Files containing {#let} blocks nested within {#each} loops may not be parseable by the standalone Svelte parser. These files are automatically skipped with a warning, preserving their original content.

This is a limitation of the Svelte compiler in standalone mode and affects files like:

{#each items as item}
  {#let value = compute(item)}
    <!-- content -->
  {/let}
{/each}

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.