UNPKG

@synergy-design-system/components

Version:

This package provides the base of the Synergy Design System as native web components. It uses [lit](https://www.lit.dev) and parts of [shoelace](https://shoelace.style/). Synergy officially supports the latest two versions of all major browsers (as define

119 lines (103 loc) 3.27 kB
/* eslint-disable import/no-extraneous-dependencies */ import { readFileSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; import { defineMetadata } from 'html-validate'; import { mergeDeep } from './mergeDeep.js'; import { rules } from './synergy-element-rules.js'; // Get the destination of the custom elements file // Note we need to use relative module imports here // as we don´t know the location of the file when it is imported const fileSystemDestinationOfCustomElements = import.meta.resolve('../../../dist/custom-elements.json'); const metadata = JSON.parse(readFileSync(fileURLToPath(fileSystemDestinationOfCustomElements), 'utf-8')); /** * Creates the attributes for a given declaration * @returns {Record<string, import('html-validate').MetaAttribute>} */ const createAttributes = (declaration) => { const attributes = (declaration.attributes || []) .filter(attr => !!attr?.type?.text) .map(attr => { // Special case for boolean attributes if (attr.type.text === 'boolean') { return { [attr.name]: { boolean: true, }, }; } // Special case for attributes that have a fixed set of values if (attr.type.text.includes('|')) { const values = attr .type .text .split('|') .filter(value => value.includes("'")) .map(value => value.trim().replaceAll("'", '')) .filter(Boolean); if (values.length === 0) { return { [attr.name]: {}, }; } return { [attr.name]: { enum: values, omit: false, }, }; } // Value is a number if (attr.type.text === 'number') { return { [attr.name]: { enum: [/^[+-]?(\d+(\.\d*)?|\.\d+)$/], }, }; } // Default case, just flag all empty values as invalid, // e.g. <syn-input value=""> is invalid, as is <syn-input value> return { [attr.name]: { enum: [/.+/], }, }; }) .filter(Boolean) .reduce((acc, curr) => ({ ...acc, ...curr, }), {}); return attributes; }; const createTextContent = (declaration) => { const { slots } = declaration; // If the element does not have slots, disallow text content if (!slots || slots.length === 0) { return 'none'; } return 'default'; }; const createMetaElement = (declaration) => ({ ...rules[declaration.name], attributes: mergeDeep( createAttributes(declaration), rules[declaration.name]?.attributes || {}, ), textContent: createTextContent(declaration), }); export const createMetaData = () => { const elements = metadata .modules .filter(module => module.declarations.filter(kind => kind === 'class')) .map(module => module.declarations) .flatMap(declaration => declaration) .map(declaration => [declaration.tagName, createMetaElement(declaration)]); const output = Object.fromEntries(elements); // console.log(JSON.stringify(output, null, 2)); return output; }; export const createElements = () => defineMetadata({ ...createMetaData(), }); // Enable for debugging // console.log(createMetaData());