This tool validates your Custom Elements Manifest to ensure your web components are properly documented and configured for optimal compatibility with IDEs, documentation tools, and component catalogs.
The validator checks two main areas:
- Package.json Configuration - Ensures your package is properly configured with correct entry points, module types, and custom elements manifest references
- Custom Elements Manifest - Validates that your manifest has proper schema versions, module paths, type definitions, and exports for each component
To install the package, use the following command:
npm install -D @wc-toolkit/cem-validatorThis package can be used in two ways:
- As a standalone script - Run validation programmatically in your build process
- As a CEM Analyzer plugin - Automatically validate during manifest generation
Run the validator as part of your build process or as a standalone validation step:
// validate-manifest.ts
import { validateCem, type CemValidatorOptions } from "@wc-toolkit/cem-validator";
import manifest from "./custom-elements.json" with { type: 'json' };
const options: CemValidatorOptions = {
packageJsonPath: "./package.json",
cemFileName: "custom-elements.json",
logErrors: false, // Set to true to log errors instead of throwing an exception
exclude: ["MyInternalComponent"], // Skip validation for specific components
rules: { // Override default severity levels for validation
packageJson: {
packageType: "off",
customElementsProperty: "error",
},
manifest: {
tagName: "error",
exportTypes: "warning",
}
}
};
try {
validateCem(manifest, options);
console.log("âś… Manifest validation passed!");
} catch (error) {
console.error("❌ Manifest validation failed:", error);
process.exit(1);
}Integrate validation directly into your manifest generation workflow:
// custom-elements-manifest.config.js
import { cemValidatorPlugin } from "@wc-toolkit/cem-validator";
export default {
plugins: [
cemValidatorPlugin({
logErrors: true, // Log errors without stopping the build
exclude: ["BaseComponent", "InternalMixin"], // Skip base classes
rules: { // Override default severity levels for validation
packageJson: {
exports: "off",
customElementsProperty: "error",
},
manifest: {
schemaVersion: "error",
tagName: "error",
modulePath: "error",
}
}
})
],
};Then run the analyzer:
npx @custom-elements-manifest/analyzer analyze- Type:
string - Default:
"./package.json" - Description: Path to your package.json file. Used to validate package configuration.
{
packageJsonPath: "./package.json"
}- Type:
string - Default:
"custom-elements.json" - Description: Name of your Custom Elements Manifest file. Used to verify the manifest is properly referenced in package.json.
{
cemFileName: "custom-elements.json"
}- Type:
boolean - Default:
false - Description: When
true, validation errors are logged to the console instead of throwing exceptions. Useful for CI/CD pipelines where you want to see all errors without stopping the process.
{
logErrors: true // Logs errors but doesn't throw
}- Type:
string[] - Default:
[] - Description: Array of component class names to exclude from validation. Useful for base classes, mixins, or internal components that don't need full validation.
{
exclude: [
"MyBaseElement", // Skip base classes
"InternalMixin", // Skip mixins
"DeprecatedComponent" // Skip deprecated components
]
}Example: If you have a base component that other components extend:
// my-base.ts
export class MyBaseElement extends HTMLElement {
// Base functionality
}
// my-button.ts
export class MyButton extends MyBaseElement {
// This will be validated
}// Validation config
{
exclude: ["MyBaseElement"] // Only validate MyButton, skip MyBaseElement
}- Type:
boolean - Default:
false - Description: Enables verbose logging during the validation process. Helpful for troubleshooting validation issues.
{
debug: true // Logs detailed validation steps
}- Type:
boolean - Default:
false - Description: Completely disables the validator. Useful for conditional execution in different environments.
{
skip: process.env.NODE_ENV === "development" // Skip validation in dev
}- Type:
Rules - Description: Configure which validations to run and their severity levels. Each rule can be set to
"off","warning", or"error".
Rules are organized into two categories: packageJson and manifest.
These rules validate your package.json configuration:
- Default:
"error" - Description: Ensures the
typefield is set to"module"for ESM packages.
{
rules: {
packageJson: {
packageType: "error" // Requires "type": "module" in package.json
}
}
}- Default:
"error" - Description: Validates the
mainfield points to a valid entry point file.
{
rules: {
packageJson: {
main: "error" // Requires valid "main": "./dist/index.js"
}
}
}- Default:
"error" - Description: Validates the
modulefield points to a valid ESM entry point.
{
rules: {
packageJson: {
module: "error" // Requires valid "module": "./dist/index.js"
}
}
}- Default:
"error" - Description: Validates the
typesfield points to a valid TypeScript declaration file.
{
rules: {
packageJson: {
types: "error" // Requires valid "types": "./dist/index.d.ts"
}
}
}- Default:
"error" - Description: Validates the package has an
exportsfield properly configured for modern package resolution.
{
rules: {
packageJson: {
exports: "error" // Requires "exports" field in package.json
}
}
}- Default:
"error" - Description: Validates the
customElementsfield in package.json points to your manifest file.
{
rules: {
packageJson: {
customElementsProperty: "error" // Requires "customElements": "./custom-elements.json"
}
}
}- Default:
"error" - Description: Validates that the Custom Elements Manifest is included in the published package (not excluded by
.npmignoreorfilesfield).
{
rules: {
packageJson: {
publishedCem: "error" // Ensures manifest is published with package
}
}
}These rules validate your Custom Elements Manifest:
- Default:
"error" - Description: Validates the manifest uses the latest schema version.
{
rules: {
manifest: {
schemaVersion: "error" // Ensures latest schema version
}
}
}- Default:
"error" - Description: Validates each component has a valid module path that exists.
{
rules: {
manifest: {
modulePath: "error" // Ensures "./src/my-button.ts" exists
}
}
}- Default:
"error" - Description: Validates each component has a valid path to its definition/implementation.
{
rules: {
manifest: {
definitionPath: "error" // Ensures component definition is valid
}
}
}- Default:
"error" - Description: Validates each component has a valid TypeScript declaration file path.
{
rules: {
manifest: {
typeDefinitionPath: "error" // Ensures "./dist/my-button.d.ts" exists
}
}
}- Default:
"error" - Description: Validates that all necessary types are exported from the module.
{
rules: {
manifest: {
exportTypes: "warning" // Warns if types aren't exported
}
}
}- Default:
"error" - Description: Validates each custom element has a tag name defined.
{
rules: {
manifest: {
tagName: "error" // Requires <my-button> tag name
}
}
}Here's a comprehensive example showing all options:
import { validateCem, type CemValidatorOptions } from "@wc-toolkit/cem-validator";
import manifest from "./custom-elements.json" with { type: 'json' };
const options: CemValidatorOptions = {
// File paths
packageJsonPath: "./package.json",
cemFileName: "custom-elements.json",
// Behavior
logErrors: false,
debug: false,
skip: false,
// Exclude specific components
exclude: [
"BaseElement",
"InternalMixin"
],
// Rule configuration
rules: {
packageJson: {
packageType: "error",
main: "error",
module: "error",
types: "error",
exports: "error",
customElementsProperty: "error",
publishedCem: "error"
},
manifest: {
schemaVersion: "error",
modulePath: "error",
definitionPath: "error",
typeDefinitionPath: "error",
exportTypes: "warning",
tagName: "error"
}
}
};
validateCem(manifest, options);Each rule supports three severity levels:
"off"- Disables the rule completely"warning"- Logs a warning but doesn't fail validation"error"- Fails validation and throws an error (or logs iflogErrors: true)
{
rules: {
manifest: {
tagName: "error", // Fails validation
exportTypes: "warning", // Shows warning only
modulePath: "off" // Skips this check
}
}
}type CemValidatorOptions = {
/** The path to the `package.json` file */
packageJsonPath?: string;
/** Custom Elements Manifest file name */
cemFileName?: string;
/** This will log errors rather throw an exception */
logErrors?: boolean;
/** List of classes to exclude from validation */
exclude?: string[];
/** Enables logging during the component loading process */
debug?: boolean;
/** Prevents plugin from executing */
skip?: boolean;
/** Rule configurations */
rules?: Rules;
};
/** The severity level for each rule */
type Severity = "off" | "warning" | "error";
type Rules = {
/** Checks if the package.json file is appropriately configured */
packageJson?: {
/** Is `type` property set to "module" */
packageType?: Severity;
/** Is `main` property set with a valid file path */
main?: Severity;
/** Is `module` property set with a valid file path */
module?: Severity;
/** Is `types` property set with a valid file path */
types?: Severity;
/** Does the package have a `exports` property configured */
exports?: Severity;
/** Is the `customElements` property properly configured */
customElementsProperty?: Severity;
/** Is the Custom Elements Manifest included in the published package */
publishedCem?: Severity;
};
/** Checks if the `customElementsManifest` is valid */
manifest?: {
/** Is the manifest using the latest schema version */
schemaVersion?: Severity;
/** Does the component have a valid module path */
modulePath?: Severity;
/** Does the component have a valid definition path */
definitionPath?: Severity;
/** Does the element have a valid type definition path */
typeDefinitionPath?: Severity;
/** Does the component export all necessary types */
exportTypes?: Severity;
/** Does the component have a tag name defined */
tagName?: Severity;
};
};Check out the documentation to see how to configure this to meet your project's needs.
