angular-cem-generator
v1.0.1
Published
Generate Angular wrapper components from Custom Element Manifest (CEM) JSON
Maintainers
Readme
Angular CEM Generator
Generate Angular wrapper components from Custom Element Manifest (CEM) JSON files.
Overview
This package takes a Custom Element Manifest JSON file as input and automatically generates strongly-typed Angular wrapper components for your web components. The generated components provide:
- ✨ Strong typing - Full TypeScript support with proper types
- 🎯 Property binding - Two-way binding support for all properties
- 📢 Event emitters - Angular EventEmitter for all custom events
- 🔄 Change detection - OnPush strategy for optimal performance
- 🚀 Standalone components - No NgModule required
- 📝 JSDoc comments - Preserves descriptions and default values
Installation
pnpm add angular-cem-generatorUsage
Basic Example
import { generateAngularComponents } from 'angular-cem-generator';
await generateAngularComponents({
manifestPath: './custom-elements.json',
outputDir: './src/components',
componentCorePackage: '@my-org/web-components',
standalone: true,
inlineProperties: true,
});Configuration Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| manifestPath | string | required | Path to the Custom Element Manifest JSON file |
| outputDir | string | required | Output directory for generated Angular components |
| componentCorePackage | string | required | Name of the package containing the web components |
| standalone | boolean | true | Generate standalone Angular components |
| inlineProperties | boolean | true | Include inline property declarations with types |
Generated Files
The generator creates the following file structure:
output/
├── proxies.ts # Angular wrapper components
├── components.d.ts # TypeScript type definitions
├── index.ts # Barrel export file
└── angular-component-lib/
└── utils.ts # Runtime utilities (ProxyCmp decorator)Example: Using Generated Components in Angular
Given a Custom Element Manifest with a data-table component:
// Import the generated components
import { DataTable } from './components';
@Component({
selector: 'app-root',
standalone: true,
imports: [DataTable],
template: `
<data-table
[data]="tableData"
[sortable]="true"
[pageSize]="20"
(rowClick)="handleRowClick($event)"
(sortChange)="handleSort($event)"
></data-table>
`
})
export class AppComponent {
tableData = [
{ id: 1, name: 'Alice', age: 30 },
{ id: 2, name: 'Bob', age: 25 },
];
handleRowClick(event: CustomEvent) {
console.log('Row clicked:', event.detail);
}
handleSort(event: CustomEvent) {
console.log('Sort changed:', event.detail);
}
}Custom Element Manifest Format
The generator expects a standard CEM JSON file following the schema version 2.0+.
Example manifest structure:
{
"schemaVersion": "2.1.0",
"modules": [
{
"kind": "javascript-module",
"path": "src/my-button.ts",
"declarations": [
{
"kind": "class",
"name": "MyButton",
"tagName": "my-button",
"customElement": true,
"members": [
{
"kind": "field",
"name": "label",
"type": { "text": "string" },
"default": "'Click me'"
}
],
"events": [
{
"name": "button-click",
"type": { "text": "CustomEvent<void>" }
}
]
}
]
}
]
}Generating a CEM
You can generate a Custom Element Manifest using tools like:
- @custom-elements-manifest/analyzer - Analyzes your source code
- Lit CLI - Built-in for Lit projects
Example using the analyzer:
npx @custom-elements-manifest/analyzerFeatures
Property Binding
All component properties are available as Angular inputs with full type checking:
// Generated component has typed properties
<my-component [disabled]="false" [label]="'Hello'"></my-component>Event Handling
Custom events are converted to Angular EventEmitters with camelCase names:
// 'button-click' event becomes 'buttonClick' output
<my-button (buttonClick)="handleClick($event)"></my-button>Type Safety
The generator creates TypeScript interfaces that match your web component definitions:
import { Components } from './components';
// Fully typed component interface
const tableProps: Components.DataTable = {
data: [...],
sortable: true,
// ... TypeScript will validate all properties
};JSDoc Preservation
Comments and descriptions from your CEM are preserved in the generated code:
/**
* Enable or disable sorting functionality.
* @default true
*/
set sortable(val: boolean) {
this.el['sortable'] = val;
}Example Project
Check out the examples directory for a complete working example with:
- Complex CEM JSON file with 3 feature-rich components
- Generation script
- Example usage in Angular
Run the example:
pnpm exampleHow It Works
- Parse - Reads and parses the Custom Element Manifest JSON
- Transform - Converts CEM metadata to internal component format
- Generate - Creates Angular component wrapper code with:
@Componentdecorator with proper configuration@ProxyCmpdecorator for property/method proxying- EventEmitter outputs for all custom events
- Inline property setters with TypeScript types
- Write - Outputs TypeScript files ready to use in Angular
Comparison with Stencil Angular Output Target
This package is inspired by @stencil/angular-output-target but works with the standard Custom Element Manifest format instead of Stencil's internal metadata. This means it can be used with:
- Lit components
- Plain web components
- Any framework that generates CEM JSON
Contributing
Contributions are welcome! Please feel free to submit issues or pull requests.
License
MIT
