cb7d0b83a8
## PR description This PR: - Creates a TypeScript-based extractor that discovers all exported twenty-ui components by scanning barrel files, extracting props/slots/events via ts-morph type analysis, and generating the remote DOM bindings automatically. - Adds a new ESLint rule which enforces all *Props types in twenty-ui components to be exported, which is required for the extractor to discover component prop types. Existing twenty-ui components are updated to comply with this rule. - Extends the remote DOM generation to support slots, per-component events, forwardRef wrappers, and richer property types (array, object, function) ## Edge cases to fix in another PR - Icons cannot be rendered inside buttons - IconButtons throw an error when mounted - MenuItems are not displayed correctly - MenuItemNavigate throws on click ## Video Demo https://github.com/user-attachments/assets/c2ed67cf-6a15-4896-9fec-e83fac0e862b
120 lines
3.2 KiB
TypeScript
120 lines
3.2 KiB
TypeScript
/**
|
|
* @jest-environment node
|
|
*/
|
|
import { RuleTester } from 'eslint';
|
|
|
|
import { rule, RULE_NAME } from './export-component-props';
|
|
|
|
const typescriptParser = require('@typescript-eslint/parser');
|
|
|
|
const ruleTester = new RuleTester({
|
|
languageOptions: {
|
|
parser: typescriptParser,
|
|
parserOptions: {
|
|
ecmaFeatures: {
|
|
jsx: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
ruleTester.run(RULE_NAME, rule as any, {
|
|
valid: [
|
|
{
|
|
name: 'Props type is already exported',
|
|
code: `
|
|
export type MyComponentProps = { label: string };
|
|
`,
|
|
},
|
|
{
|
|
name: 'Props interface is already exported',
|
|
code: `
|
|
export interface MyComponentProps { label: string }
|
|
`,
|
|
},
|
|
{
|
|
name: 'Type that doesn\'t end with Props is ignored',
|
|
code: `
|
|
type MyComponentOptions = { flag: boolean };
|
|
`,
|
|
},
|
|
{
|
|
name: 'Interface that doesn\'t end with Props is ignored',
|
|
code: `
|
|
interface MyComponentConfig { flag: boolean }
|
|
`,
|
|
},
|
|
{
|
|
name: 'Props re-exported via export { FooProps } is treated as exported',
|
|
code: `
|
|
type MyComponentProps = { label: string };
|
|
export { MyComponentProps };
|
|
`,
|
|
},
|
|
{
|
|
name: 'Non-Props type is not required to be exported',
|
|
code: `
|
|
type InternalState = { count: number };
|
|
`,
|
|
},
|
|
],
|
|
invalid: [
|
|
{
|
|
name: 'Unexported Props type alias',
|
|
code: `
|
|
type MyComponentProps = { label: string };
|
|
`,
|
|
errors: [{ messageId: 'mustExportProps' }],
|
|
output: `
|
|
export type MyComponentProps = { label: string };
|
|
`,
|
|
},
|
|
{
|
|
name: 'Unexported Props interface',
|
|
code: `
|
|
interface MyComponentProps { label: string }
|
|
`,
|
|
errors: [{ messageId: 'mustExportProps' }],
|
|
output: `
|
|
export interface MyComponentProps { label: string }
|
|
`,
|
|
},
|
|
{
|
|
name: 'Unexported Props type used in a component',
|
|
code: `
|
|
type MyComponentProps = { label: string };
|
|
export const MyComponent = ({ label }: MyComponentProps) => <div>{label}</div>;
|
|
`,
|
|
errors: [{ messageId: 'mustExportProps' }],
|
|
output: `
|
|
export type MyComponentProps = { label: string };
|
|
export const MyComponent = ({ label }: MyComponentProps) => <div>{label}</div>;
|
|
`,
|
|
},
|
|
{
|
|
name: 'Unexported Props type with non-exported component',
|
|
code: `
|
|
type MyComponentProps = { label: string };
|
|
const MyComponent = ({ label }: MyComponentProps) => <div>{label}</div>;
|
|
`,
|
|
errors: [{ messageId: 'mustExportProps' }],
|
|
output: `
|
|
export type MyComponentProps = { label: string };
|
|
const MyComponent = ({ label }: MyComponentProps) => <div>{label}</div>;
|
|
`,
|
|
},
|
|
{
|
|
name: 'Unexported Props type defined after the component',
|
|
code: `
|
|
export const MyComponent = ({ label }: MyComponentProps) => <div>{label}</div>;
|
|
type MyComponentProps = { label: string };
|
|
`,
|
|
errors: [{ messageId: 'mustExportProps' }],
|
|
output: `
|
|
export const MyComponent = ({ label }: MyComponentProps) => <div>{label}</div>;
|
|
export type MyComponentProps = { label: string };
|
|
`,
|
|
},
|
|
],
|
|
});
|