WCP ESLint Plugin
@staticbolt/wcp-eslint-plugin is an ESLint plugin for authoring web components with the @staticbolt/wcp-core build system. It enforces patterns and constraints specific to WCP components, covering custom element conventions, build-time compatibility, DOM API usage, and framework type generation.
The plugin integrates with any WCP-based setup, including the wcp-vite-plugin, wcp-staticbolt-plugin, and wcp-cli.
Requirements
- ESLint with flat config support (ESLint 9+)
Installation
npm install --save-dev @staticbolt/wcp-eslint-pluginConfiguration
Import the plugin and extend the recommended config in your eslint.config.js. The recommended config enables all WCP rules.
import wcp from "@staticbolt/wcp-eslint-plugin";
export default [ { files: ["path/to/components/**/*.ts"], extends: [wcp.configs.recommended], },];Overriding rules
Any rule can be overridden after extending recommended:
import wcp from "@staticbolt/wcp-eslint-plugin";
export default [ { files: ["packages/wcp/src/components/**/*.ts"], extends: [wcp.configs.recommended], rules: { "wcp/compat-dom": ["error", { available: "newly", newlyMinYears: 0.9 }], }, },];Targeting component files only
The plugin rules are designed specifically for WCP component files and should not be applied globally. Always scope the configuration to your component source files using the files glob. Applying these rules to non-component files will produce false positives.
Rules
import-as-string
Ensures that files referenced by import_as_string exist on disk.
import_as_string is a build-time function that is replaced with the contents of the HTML or CSS file passed as its first argument. Referenced files are treated as part of the component and are processed and minified alongside it. This rule reports an error if the referenced file path cannot be resolved.
custom-element-name
Enforces a valid custom element name via the _componentName static property.
Every component must declare a _componentName static property. This rule validates that:
_componentNameis defined on the class_componentNameis a string literal_componentNameis not a reserved name_componentNamedoes not start withxml_componentNamecontains at least one hyphen_componentNameis entirely lowercase_componentNamebegins with a lowercase letter, not a number or special character
compat-dom
Warns when using DOM APIs that are unsupported by your browserslist targets or below a specified baseline availability threshold.
Options
| Option | Type | Default | Description |
|---|---|---|---|
available | "widely" | "newly" | "limited" | "limited" | Baseline threshold. "widely" warns on newly and limited available APIs. "newly" warns on limited available APIs only. "limited" runs a browserslist check only, with no baseline warnings. |
browserslist | string[] | — | Browserslist targets to check against. |
partial | boolean | — | Also warn on APIs with partial browser support. |
newlyMinYears | number | — | Only applies when available is "newly". Warn if a newly-available (baseline: low) feature has been available across all browsers for fewer than this many years, computed from baseline_low_date. For example, 1 warns if the feature landed in all browsers less than one year ago. |
export-component-types
Enforces that each component file exports a corresponding [ComponentClassName]Types type.
This type is used to generate framework-specific types and must be exported from the component file. It should be defined using WCP.WComponent<typeof ClassName>.
Example:
export type AccordionTypes = WCP.WComponent<typeof Accordion>;
class Accordion extends HTMLElement implements WCP.IWebComponent { // ...}no-dynamic-css-class-name
Disallows dynamically constructed CSS class names.
At build time, CSS class names are minified and renamed. Dynamically constructed class names (e.g. via string concatenation or template literals) cannot be statically analyzed, and will not be updated during minification, causing them to break at runtime.
If this rule is disabled or suppressed with an inline comment, dynamic class names will not trigger a warning during minification and will remain unmodified. Only disable this rule when you are certain the class names are intentionally static strings that should not be renamed.
no-dynamic-css-variable
Disallows dynamically constructed CSS variable names.
At build time, CSS variable names are minified and renamed. Dynamically constructed variable names cannot be statically analyzed and will not be updated during minification, causing them to break at runtime.
If this rule is disabled or suppressed with an inline comment, dynamic variable names will not trigger a warning during minification and will remain unmodified. Only disable this rule when you are certain the variable names are intentionally static strings that should not be renamed.
no-import-export-value
Disallows importing or exporting runtime values from web component files.
At build time, component files are wrapped in an IIFE to ensure compatibility with non-module <script> tags. Importing or exporting runtime values is incompatible with this transformation. Type-only imports and exports (import type, export type) are permitted.
no-invalid-event-name
Disallows event names that are reserved, conflict with DOM events, or are incompatible with other frameworks.
Event names must consist of lowercase letters only. Hyphens, numbers, and special characters are not allowed. Event names must not start with on, as this conflicts with framework event-binding conventions (e.g. onClick, onSubmit).
Options
| Option | Type | Description |
|---|---|---|
ignored | string[] | Event names to suppress warnings for. |
extend | string[] | Additional event names to explicitly allow. |
no-this-attribute-override
Disallows setting or removing attributes on the web component’s host element.
The host element is owned and controlled by the user. Modifying its attributes from within the component (e.g. via this.setAttribute, this.removeAttribute) can produce unexpected behavior. Data flow should go in one direction only: from attribute to property.
no-this-element-selector
Disallows querying child elements directly on the web component’s host element.
Querying child elements on this (e.g. via this.querySelector) is unreliable because child elements may not have been rendered yet at the time of the call. Use slots and the slotchange event to respond to child content.
no-true-default-attribute
Disallows boolean observed attributes from defaulting to true.
Boolean HTML attributes cannot be set to false via markup — their mere presence sets them to true, and they can only be removed entirely. Defaulting a boolean attribute to true therefore creates an irreversible state: there is no way for a user to opt out using HTML alone. Boolean observed attributes must default to false or undefined.
observed-attributes
Enforces that observedAttributes is declared as a public static getter returning a tuple of string literals annotated with as const.
Using string[] as the return type loses the literal types of each attribute name, which breaks type-level integrations that depend on knowing the exact attribute strings. The as const annotation preserves the tuple’s literal types and ensures the type system can narrow correctly.
A member is considered public when it is not prefixed with #.
prefer-static-private-methods
Flags private methods and arrow function properties that do not reference this and could be declared static.
Methods that do not use this have no reason to be instance members. Marking them static makes the intent explicit, avoids unnecessary access to the instance, and can allow the engine to optimize the call.
Private members are identified by the # prefix.
arrow-public-methods
Enforces that public methods on HTMLElement subclasses are declared as readonly arrow function properties.
Regular prototype methods and arrow function class properties are structurally equivalent at runtime, but differ in how the type system treats them. Declaring public methods as readonly arrow functions allows the type system to distinguish between assignable function properties and non-assignable prototype methods, which is required for accurate framework type generation.