@withstudiocms/component-registry
v0.1.0-beta.7
Published
Component Registry Utilities for Astro
Maintainers
Readme
@withstudiocms/component-registry
Create a virtual Astro Component registry with ease.
Install
To get started using this package, simply use your package manager to install it!
npm install @withstudiocms/component-registrypnpm add @withstudiocms/component-registryyarn add @withstudiocms/component-registryUsage
Component Registry
The ComponentRegistry allows you to register Astro components and manage their prop definitions:
import { Effect } from '@withstudiocms/effect';
import { ComponentRegistry } from '@withstudiocms/component-registry';
// Create a registry instance
const registry = await Effect.runPromise(
Effect.gen(function* () {
const registry = yield* ComponentRegistry;
return registry;
}).pipe(Effect.provide(ComponentRegistry.Default))
);
// Register a component from an Astro file
await Effect.runPromise(
registry.registerComponentFromFile('./components/MyComponent.astro')
);
// Get component props
const componentProps = await Effect.runPromise(
registry.getComponentProps('MyComponent')
);
// Validate props against component definition
const validation = await Effect.runPromise(
registry.validateProps('MyComponent', {
title: 'Hello World',
count: 42
})
);
// Get all registered components
const allComponents = await Effect.runPromise(
registry.getAllComponents()
);Component Proxy
Create proxies for existing Astro components to enable dynamic rendering:
import { createComponentProxy, transformHTML } from '@withstudiocms/component-registry';
// Inside an Astro component
// body?.components contains imported Astro components from a virtual module
// Example: { 'example-comp': ExampleComp, 'foo-comp': FooComp }
const components = createComponentProxy($$result, body?.components);
// Transform HTML that contains component placeholders
if (body?.html) {
const transformedHtml = await transformHTML(
body.html,
components,
body.sanitizeOpts
);
}Runtime System
For more advanced use cases, the component registry provides a runtime system with virtual modules:
import { setupRendererComponentProxy, createRenderer } from '@withstudiocms/component-registry';
// Setup component proxy with virtual module components
const components = await setupRendererComponentProxy(result);
// Create a renderer function for HTML transformation
const renderer = await createRenderer(result, sanitizeOpts, preRenderer);
// Use the renderer to transform HTML content
const transformedHtml = await renderer(htmlContent);The runtime system automatically imports components from the virtual module 'virtual:component-registry-internal-proxy' and provides a complete rendering pipeline.
Virtual Module System
The component registry uses virtual modules to dynamically import and manage components:
// Virtual module imports (handled by the registry)
import * as registry from 'virtual:component-registry-internal-proxy';
import { componentKeys, componentProps } from 'virtual:component-registry-internal-proxy';
// Components are automatically available through the runtime system
// componentKeys: ['example_comp', 'foo_comp']
// componentProps: { 'example_comp': ComponentProps, 'foo_comp': ComponentProps }HTML Transformation
Transform HTML strings with component swapping and sanitization:
import { transformHTML } from '@withstudiocms/component-registry';
const html = `
<div>
<my-button text="Click me"></my-button>
<my-card title="Hello" content="World"></my-card>
</div>
`;
const components = {
'my-button': (props: { text: string }) =>
`<button class="btn">${props.text}</button>`,
'my-card': (props: { title: string; content: string }) =>
`<div class="card"><h3>${props.title}</h3><p>${props.content}</p></div>`
};
// Transform with sanitization
const result = await transformHTML(html, components, {
allowedElements: ['div', 'button', 'h3', 'p', 'my-button', 'my-card'],
allowedAttributes: {
'*': ['class'],
'my-button': ['text'],
'my-card': ['title', 'content']
}
});Prop Parsing and Validation
The registry automatically parses TypeScript interfaces and JSDoc comments:
// Astro component with JSDoc comments
// components/UserCard.astro
---
/**
* User card component for displaying user information
*/
interface Props {
/** The user's display name */
name: string;
/** The user's avatar URL */
avatar?: string;
/** Whether the user is online */
isOnline: boolean;
}
const { name, avatar, isOnline } = Astro.props;
---
<div class="user-card">
{avatar && <img src={avatar} alt={name} />}
<h3>{name}</h3>
<span class="status">{isOnline ? 'Online' : 'Offline'}</span>
</div>// Register and validate
await Effect.runPromise(
registry.registerComponentFromFile('./components/UserCard.astro')
);
const validation = await Effect.runPromise(
registry.validateProps('UserCard', {
name: 'John Doe',
avatar: 'https://example.com/avatar.jpg',
isOnline: true
})
);
console.log(validation.valid); // true
console.log(validation.errors); // []Utilities
The package provides various utility functions:
import {
convertHyphensToUnderscores,
convertUnderscoresToHyphens,
dedent,
integrationLogger
} from '@withstudiocms/component-registry';
// String conversion utilities
const underscored = convertHyphensToUnderscores('my-component'); // 'my_component'
const hyphenated = convertUnderscoresToHyphens('my_component'); // 'my-component'
// Remove leading indentation
const cleanText = dedent(`
This text has
leading indentation
that will be removed
`);
// Integration logging
await integrationLogger({
logLevel: 'info',
logger: astroLogger,
verbose: true
}, 'Component registered successfully');API Reference
ComponentRegistry
The main registry class for managing Astro components.
Methods
registerComponentFromFile(filePath: string, componentName?: string): Register a component from an Astro filegetComponentProps(componentName: string): Get the props definition for a componentvalidateProps(componentName: string, props: Record<string, unknown>): Validate props against component definitiongetAllComponents(): Get all registered components
createComponentProxy
Creates a proxy for components that can be either strings or functions.
function createComponentProxy(
result: SSRResult,
components: ComponentType = {}
): ComponentTypetransformHTML
Transforms HTML with component swapping and sanitization.
function transformHTML(
html: string,
components: ComponentType,
sanitizeOpts?: SanitizeOptions
): Promise<string>Error Handling
The package uses Effect-ts for error handling:
import { ComponentNotFoundError, FileParseError } from '@withstudiocms/component-registry';
try {
await Effect.runPromise(registry.getComponentProps('NonExistentComponent'));
} catch (error) {
if (error instanceof ComponentNotFoundError) {
console.log('Component not found:', error.componentName);
}
}TypeScript Support
All functions and classes are fully typed with TypeScript:
import type {
AstroComponentProps,
ComponentRegistryEntry,
PropValidationResult
} from '@withstudiocms/component-registry';
// Use types in your code
const component: AstroComponentProps = {
name: 'MyComponent',
props: [
{
name: 'title',
type: 'string',
optional: false,
description: 'The component title'
}
]
};