{"id":18004,"library":"web-component-analyzer","title":"Web Component Analyzer CLI","description":"`web-component-analyzer` is a command-line interface (CLI) tool designed to analyze web component source code, including both JavaScript and TypeScript, to extract structured metadata. It parses code and JSDoc comments to identify and document `properties`, `attributes`, `methods`, `events`, `slots`, `CSS shadow parts`, and `CSS custom properties`. The tool supports vanilla web components and provides specialized analysis for components built with frameworks like LitElement, Polymer, Stencil (partial), and LWC. The current stable version is 2.0.0. While there isn't a strict regular release cadence, updates are made to enhance parsing logic, fix bugs, and add support for new Web Component features or framework nuances. Its primary differentiation lies in its comprehensive extraction capabilities across multiple web component ecosystems, outputting to formats like Markdown, JSON, and VS Code-specific schemas, making it useful for documentation generation and IDE tooling workflows. It explicitly handles complexities like mixins and JSDoc type definitions, improving accuracy over simple regex-based parsers, and ships with TypeScript types for programmatic integration.","status":"active","version":"2.0.0","language":"javascript","source_language":"en","source_url":"https://github.com/runem/web-component-analyzer","tags":["javascript","web components","web","components","typescript"],"install":[{"cmd":"npm install web-component-analyzer","lang":"bash","label":"npm"},{"cmd":"yarn add web-component-analyzer","lang":"bash","label":"yarn"},{"cmd":"pnpm add web-component-analyzer","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Required for parsing JavaScript and TypeScript source files, as the analyzer internally uses the TypeScript compiler API.","package":"typescript","optional":false}],"imports":[{"note":"Main function for programmatically analyzing a single string of web component code. `web-component-analyzer` is an ESM-first package.","wrong":"const analyzeText = require('web-component-analyzer')","symbol":"analyzeText","correct":"import { analyzeText } from 'web-component-analyzer'"},{"note":"Use this for programmatically analyzing multiple web component files based on glob patterns. It's a named export.","wrong":"import analyzeGlobs from 'web-component-analyzer'","symbol":"analyzeGlobs","correct":"import { analyzeGlobs } from 'web-component-analyzer'"},{"note":"Utility class for logging analysis progress and errors to the console, useful when building custom CLI tools or integrating programmatically with verbose output.","wrong":null,"symbol":"ConsoleLogger","correct":"import { ConsoleLogger } from 'web-component-analyzer'"}],"quickstart":{"code":"import { analyzeText } from 'web-component-analyzer';\n\nconst componentCode = `\n/**\n * A simple counter element.\n * @slot default - The content rendered inside the counter.\n * @csspart button - The button part.\n * @prop {number} count - The current count.\n * @attr {string} label - A label for the counter.\n * @fires count-changed - Emitted when the count changes.\n */\nclass MyCounter extends HTMLElement {\n  static get observedAttributes() {\n    return ['label'];\n  }\n\n  constructor() {\n    super();\n    this.count = 0;\n    this.attachShadow({ mode: 'open' });\n  }\n\n  connectedCallback() {\n    this.shadowRoot.innerHTML = `\n      <style>\n        :host { display: block; padding: 16px; border: 1px solid #ccc; }\n        .wrapper { display: flex; align-items: center; gap: 8px; }\n        button { padding: 8px 16px; cursor: pointer; }\n      </style>\n      <div class=\"wrapper\">\n        <span part=\"button\">${this.label || 'Counter'}: ${this.count}</span>\n        <button id=\"increment\">Increment</button>\n      </div>\n    `;\n    this.shadowRoot.querySelector('#increment')?.addEventListener('click', this._onIncrement.bind(this));\n  }\n\n  attributeChangedCallback(name, oldValue, newValue) {\n    if (name === 'label') {\n      this.label = newValue;\n      if (this.shadowRoot) {\n        this.shadowRoot.querySelector('span').textContent = `${this.label}: ${this.count}`;\n      }\n    }\n  }\n\n  _onIncrement() {\n    this.count++;\n    if (this.shadowRoot) {\n        this.shadowRoot.querySelector('span').textContent = `${this.label || 'Counter'}: ${this.count}`;\n    }\n    this.dispatchEvent(new CustomEvent('count-changed', { detail: this.count }));\n  }\n}\n\ncustomElements.define('my-counter', MyCounter);\n`;\n\nasync function analyzeMyComponent() {\n  try {\n    const result = await analyzeText(componentCode, {\n      fileName: 'my-counter.js',\n      // 'defaultPackage' can be used to set properties for the default package in the manifest\n      defaultPackage: { name: 'my-components', version: '1.0.0' }\n    });\n\n    if (result && result.length > 0) {\n      console.log(\"Analysis Result for 'my-counter':\");\n      console.log(JSON.stringify(result[0], null, 2));\n      console.log(\"\\nProperties found:\", result[0].declarations?.[0]?.members?.filter(m => m.kind === 'field' || m.kind === 'property').map(p => p.name));\n    } else {\n      console.log(\"No components found in the provided code.\");\n    }\n  } catch (error) {\n    console.error(\"Error analyzing component:\", error);\n  }\n}\n\nanalyzeMyComponent();","lang":"typescript","description":"Demonstrates programmatic analysis of a single web component string using `analyzeText`, extracting its metadata including properties, attributes, events, slots, and CSS parts, then logging the structured output."},"warnings":[{"fix":"Consult the official GitHub repository for detailed 2.0.0 release notes, if available, or review the source code for changes to the analysis API and output format. Adapt programmatic integrations accordingly.","message":"The jump to version 2.0.0, despite not having explicit breaking change notes in the provided changelog, typically indicates potential breaking changes, especially for the programmatic API or the structure of the JSON output, which was previously experimental. Users upgrading from 1.x should test thoroughly.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Always use the latest stable version of `web-component-analyzer` to ensure the most consistent JSON output, and robustify your parsing logic to handle potential schema evolution.","message":"The JSON output format was considered 'experimental' in earlier versions (e.g., prior to v1.1.0), meaning its structure could change without being explicitly flagged as a breaking change in minor versions. Relying on a fixed JSON schema in older versions might lead to unexpected parsing errors.","severity":"gotcha","affected_versions":"<2.0.0"},{"fix":"Update to `web-component-analyzer` version 1.0.2 or newer to resolve known globbing issues on Windows. If problems persist, consider providing explicit file paths instead of globs.","message":"Older versions (prior to v1.0.2) had known issues with CLI globbing on Windows, which could lead to files not being analyzed correctly or analysis failures.","severity":"gotcha","affected_versions":"<1.0.2"},{"fix":"Ensure you are on `web-component-analyzer` v1.1.0 or newer for improved JSDoc parsing accuracy. Review your JSDoc comments to match supported formats.","message":"JSDoc parsing for specific tags like `@fires` with type information (e.g., `@fires my-event {MouseEvent}`) was improved in v1.1.0. Older versions might not correctly parse such detailed JSDoc entries, leading to incomplete metadata.","severity":"gotcha","affected_versions":"<1.1.0"}],"env_vars":null,"last_verified":"2026-04-23T00:00:00.000Z","next_check":"2026-07-22T00:00:00.000Z","problems":[{"fix":"Ensure your web component is correctly defined and registered (e.g., `customElements.define('my-element', MyElement);`) and that the analyzer's glob pattern or input text covers the definition.","cause":"No `customElements.define` call or other recognized web component definition pattern was found in the analyzed source code.","error":"Error: Could not find any custom elements in the specified files."},{"fix":"Always check if the analysis result is defined and not empty before attempting to access its properties. Use optional chaining (`?.`) for safer property access.","cause":"Attempting to access properties on an `undefined` analysis result, often because `analyzeText` or `analyzeGlobs` returned an empty array or an unexpected structure.","error":"TypeError: Cannot read properties of undefined (reading 'map')"},{"fix":"Verify CLI option spellings and casing against the documentation (`--outFile`, `--outDir`, `--format`). Most options use camelCase.","cause":"Incorrect casing or spelling for CLI options. The correct option is `--outFile` (camelCase).","error":"Error: Unknown option `--out-file`"},{"fix":"Check the specified file for syntax errors. Ensure your TypeScript configuration (if programmatic) or environment supports the language features used. Verify file paths and permissions.","cause":"Syntax errors in the source file, unsupported JavaScript/TypeScript features in the configured TypeScript parser, or issues with file access.","error":"Error: Parsing failed for file <filename>"}],"ecosystem":"npm","meta_description":null,"install_score":null,"install_tag":null,"quickstart_score":null,"quickstart_tag":null}