Skip to content

A tool to validate the content of the Custom Elements Manifest to ensure the CEM and components are properly configured

License

Notifications You must be signed in to change notification settings

wc-toolkit/cem-validator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

48 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

workbench with tools, html, css, javascript, and download icon

WC Toolkit - CEM Validator

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.

What Does It Validate?

The validator checks two main areas:

  1. Package.json Configuration - Ensures your package is properly configured with correct entry points, module types, and custom elements manifest references
  2. Custom Elements Manifest - Validates that your manifest has proper schema versions, module paths, type definitions, and exports for each component

Installation

To install the package, use the following command:

npm install -D @wc-toolkit/cem-validator

Usage

This package can be used in two ways:

  1. As a standalone script - Run validation programmatically in your build process
  2. As a CEM Analyzer plugin - Automatically validate during manifest generation

Script Usage

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);
}

CEM Analyzer Plugin

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

Configuration

Options

packageJsonPath

  • Type: string
  • Default: "./package.json"
  • Description: Path to your package.json file. Used to validate package configuration.
{
  packageJsonPath: "./package.json"
}

cemFileName

  • 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"
}

logErrors

  • 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
}

exclude

  • 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
}

debug

  • Type: boolean
  • Default: false
  • Description: Enables verbose logging during the validation process. Helpful for troubleshooting validation issues.
{
  debug: true // Logs detailed validation steps
}

skip

  • 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
}

rules

  • Type: Rules
  • Description: Configure which validations to run and their severity levels. Each rule can be set to "off", "warning", or "error".

Rules Configuration

Rules are organized into two categories: packageJson and manifest.

Package.json Rules

These rules validate your package.json configuration:

packageType
  • Default: "error"
  • Description: Ensures the type field is set to "module" for ESM packages.
{
  rules: {
    packageJson: {
      packageType: "error" // Requires "type": "module" in package.json
    }
  }
}
main
  • Default: "error"
  • Description: Validates the main field points to a valid entry point file.
{
  rules: {
    packageJson: {
      main: "error" // Requires valid "main": "./dist/index.js"
    }
  }
}
module
  • Default: "error"
  • Description: Validates the module field points to a valid ESM entry point.
{
  rules: {
    packageJson: {
      module: "error" // Requires valid "module": "./dist/index.js"
    }
  }
}
types
  • Default: "error"
  • Description: Validates the types field points to a valid TypeScript declaration file.
{
  rules: {
    packageJson: {
      types: "error" // Requires valid "types": "./dist/index.d.ts"
    }
  }
}
exports
  • Default: "error"
  • Description: Validates the package has an exports field properly configured for modern package resolution.
{
  rules: {
    packageJson: {
      exports: "error" // Requires "exports" field in package.json
    }
  }
}
customElementsProperty
  • Default: "error"
  • Description: Validates the customElements field in package.json points to your manifest file.
{
  rules: {
    packageJson: {
      customElementsProperty: "error" // Requires "customElements": "./custom-elements.json"
    }
  }
}
publishedCem
  • Default: "error"
  • Description: Validates that the Custom Elements Manifest is included in the published package (not excluded by .npmignore or files field).
{
  rules: {
    packageJson: {
      publishedCem: "error" // Ensures manifest is published with package
    }
  }
}

Manifest Rules

These rules validate your Custom Elements Manifest:

schemaVersion
  • Default: "error"
  • Description: Validates the manifest uses the latest schema version.
{
  rules: {
    manifest: {
      schemaVersion: "error" // Ensures latest schema version
    }
  }
}
modulePath
  • Default: "error"
  • Description: Validates each component has a valid module path that exists.
{
  rules: {
    manifest: {
      modulePath: "error" // Ensures "./src/my-button.ts" exists
    }
  }
}
definitionPath
  • Default: "error"
  • Description: Validates each component has a valid path to its definition/implementation.
{
  rules: {
    manifest: {
      definitionPath: "error" // Ensures component definition is valid
    }
  }
}
typeDefinitionPath
  • Default: "error"
  • Description: Validates each component has a valid TypeScript declaration file path.
{
  rules: {
    manifest: {
      typeDefinitionPath: "error" // Ensures "./dist/my-button.d.ts" exists
    }
  }
}
exportTypes
  • Default: "error"
  • Description: Validates that all necessary types are exported from the module.
{
  rules: {
    manifest: {
      exportTypes: "warning" // Warns if types aren't exported
    }
  }
}
tagName
  • Default: "error"
  • Description: Validates each custom element has a tag name defined.
{
  rules: {
    manifest: {
      tagName: "error" // Requires <my-button> tag name
    }
  }
}

Complete Configuration Example

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);

Severity Levels

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 if logErrors: true)
{
  rules: {
    manifest: {
      tagName: "error",        // Fails validation
      exportTypes: "warning",  // Shows warning only
      modulePath: "off"        // Skips this check
    }
  }
}

Type Definitions

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.

About

A tool to validate the content of the Custom Elements Manifest to ensure the CEM and components are properly configured

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •