style: format all files with prettier

This commit is contained in:
Seth Hobson
2026-01-19 17:07:03 -05:00
parent 8d37048deb
commit 56848874a2
355 changed files with 15215 additions and 10241 deletions

View File

@@ -17,12 +17,12 @@ $ARGUMENTS
```typescript
interface ComponentSpec {
name: string;
type: 'functional' | 'page' | 'layout' | 'form' | 'data-display';
type: "functional" | "page" | "layout" | "form" | "data-display";
props: PropDefinition[];
state?: StateDefinition[];
hooks?: string[];
styling: 'css-modules' | 'styled-components' | 'tailwind';
platform: 'web' | 'native' | 'universal';
styling: "css-modules" | "styled-components" | "tailwind";
platform: "web" | "native" | "universal";
}
interface PropDefinition {
@@ -43,7 +43,7 @@ class ComponentAnalyzer {
state: this.extractState(input),
hooks: this.identifyHooks(input),
styling: this.detectStylingApproach(),
platform: this.detectPlatform()
platform: this.detectPlatform(),
};
}
}
@@ -67,13 +67,13 @@ class ReactComponentGenerator {
styles: this.generateStyles(spec),
tests: options.testing ? this.generateTests(spec) : null,
stories: options.storybook ? this.generateStories(spec) : null,
index: this.generateIndex(spec)
index: this.generateIndex(spec),
};
}
generateComponent(spec: ComponentSpec, options: GeneratorOptions): string {
const imports = this.generateImports(spec, options);
const types = options.typescript ? this.generatePropTypes(spec) : '';
const types = options.typescript ? this.generatePropTypes(spec) : "";
const component = this.generateComponentBody(spec, options);
const exports = this.generateExports(spec);
@@ -83,9 +83,9 @@ class ReactComponentGenerator {
generateImports(spec: ComponentSpec, options: GeneratorOptions): string {
const imports = ["import React, { useState, useEffect } from 'react';"];
if (spec.styling === 'css-modules') {
if (spec.styling === "css-modules") {
imports.push(`import styles from './${spec.name}.module.css';`);
} else if (spec.styling === 'styled-components') {
} else if (spec.styling === "styled-components") {
imports.push("import styled from 'styled-components';");
}
@@ -93,35 +93,43 @@ class ReactComponentGenerator {
imports.push("import { useA11y } from '@/hooks/useA11y';");
}
return imports.join('\n');
return imports.join("\n");
}
generatePropTypes(spec: ComponentSpec): string {
const props = spec.props.map(p => {
const optional = p.required ? '' : '?';
const comment = p.description ? ` /** ${p.description} */\n` : '';
return `${comment} ${p.name}${optional}: ${p.type};`;
}).join('\n');
const props = spec.props
.map((p) => {
const optional = p.required ? "" : "?";
const comment = p.description ? ` /** ${p.description} */\n` : "";
return `${comment} ${p.name}${optional}: ${p.type};`;
})
.join("\n");
return `export interface ${spec.name}Props {\n${props}\n}`;
}
generateComponentBody(spec: ComponentSpec, options: GeneratorOptions): string {
const propsType = options.typescript ? `: React.FC<${spec.name}Props>` : '';
const destructuredProps = spec.props.map(p => p.name).join(', ');
generateComponentBody(
spec: ComponentSpec,
options: GeneratorOptions,
): string {
const propsType = options.typescript ? `: React.FC<${spec.name}Props>` : "";
const destructuredProps = spec.props.map((p) => p.name).join(", ");
let body = `export const ${spec.name}${propsType} = ({ ${destructuredProps} }) => {\n`;
// Add state hooks
if (spec.state) {
body += spec.state.map(s =>
` const [${s.name}, set${this.capitalize(s.name)}] = useState${options.typescript ? `<${s.type}>` : ''}(${s.initial});\n`
).join('');
body += '\n';
body += spec.state
.map(
(s) =>
` const [${s.name}, set${this.capitalize(s.name)}] = useState${options.typescript ? `<${s.type}>` : ""}(${s.initial});\n`,
)
.join("");
body += "\n";
}
// Add effects
if (spec.hooks?.includes('useEffect')) {
if (spec.hooks?.includes("useEffect")) {
body += ` useEffect(() => {\n`;
body += ` // TODO: Add effect logic\n`;
body += ` }, [${destructuredProps}]);\n\n`;
@@ -131,7 +139,7 @@ class ReactComponentGenerator {
if (options.accessibility) {
body += ` const a11yProps = useA11y({\n`;
body += ` role: '${this.inferAriaRole(spec.type)}',\n`;
body += ` label: ${spec.props.find(p => p.name === 'label')?.name || `'${spec.name}'`}\n`;
body += ` label: ${spec.props.find((p) => p.name === "label")?.name || `'${spec.name}'`}\n`;
body += ` });\n\n`;
}
@@ -145,12 +153,17 @@ class ReactComponentGenerator {
}
generateJSX(spec: ComponentSpec, options: GeneratorOptions): string {
const className = spec.styling === 'css-modules' ? `className={styles.${this.camelCase(spec.name)}}` : '';
const a11y = options.accessibility ? '{...a11yProps}' : '';
const className =
spec.styling === "css-modules"
? `className={styles.${this.camelCase(spec.name)}}`
: "";
const a11y = options.accessibility ? "{...a11yProps}" : "";
return ` <div ${className} ${a11y}>\n` +
` {/* TODO: Add component content */}\n` +
` </div>\n`;
return (
` <div ${className} ${a11y}>\n` +
` {/* TODO: Add component content */}\n` +
` </div>\n`
);
}
}
```
@@ -171,11 +184,11 @@ import {
} from 'react-native';
interface ${spec.name}Props {
${spec.props.map(p => ` ${p.name}${p.required ? '' : '?'}: ${this.mapNativeType(p.type)};`).join('\n')}
${spec.props.map((p) => ` ${p.name}${p.required ? "" : "?"}: ${this.mapNativeType(p.type)};`).join("\n")}
}
export const ${spec.name}: React.FC<${spec.name}Props> = ({
${spec.props.map(p => p.name).join(',\n ')}
${spec.props.map((p) => p.name).join(",\n ")}
}) => {
return (
<View
@@ -206,11 +219,11 @@ const styles = StyleSheet.create({
mapNativeType(webType: string): string {
const typeMap: Record<string, string> = {
'string': 'string',
'number': 'number',
'boolean': 'boolean',
'React.ReactNode': 'React.ReactNode',
'Function': '() => void'
string: "string",
number: "number",
boolean: "boolean",
"React.ReactNode": "React.ReactNode",
Function: "() => void",
};
return typeMap[webType] || webType;
}
@@ -228,7 +241,10 @@ import { ${spec.name} } from './${spec.name}';
describe('${spec.name}', () => {
const defaultProps = {
${spec.props.filter(p => p.required).map(p => ` ${p.name}: ${this.getMockValue(p.type)},`).join('\n')}
${spec.props
.filter((p) => p.required)
.map((p) => ` ${p.name}: ${this.getMockValue(p.type)},`)
.join("\n")}
};
it('renders without crashing', () => {
@@ -241,7 +257,10 @@ ${spec.props.filter(p => p.required).map(p => ` ${p.name}: ${this.getMockValu
expect(screen.getByText(/content/i)).toBeVisible();
});
${spec.props.filter(p => p.type.includes('()') || p.name.startsWith('on')).map(p => `
${spec.props
.filter((p) => p.type.includes("()") || p.name.startsWith("on"))
.map(
(p) => `
it('calls ${p.name} when triggered', () => {
const mock${this.capitalize(p.name)} = jest.fn();
render(<${spec.name} {...defaultProps} ${p.name}={mock${this.capitalize(p.name)}} />);
@@ -250,7 +269,9 @@ ${spec.props.filter(p => p.type.includes('()') || p.name.startsWith('on')).map(p
fireEvent.click(trigger);
expect(mock${this.capitalize(p.name)}).toHaveBeenCalledTimes(1);
});`).join('\n')}
});`,
)
.join("\n")}
it('meets accessibility standards', async () => {
const { container } = render(<${spec.name} {...defaultProps} />);
@@ -262,12 +283,12 @@ ${spec.props.filter(p => p.type.includes('()') || p.name.startsWith('on')).map(p
}
getMockValue(type: string): string {
if (type === 'string') return "'test value'";
if (type === 'number') return '42';
if (type === 'boolean') return 'true';
if (type.includes('[]')) return '[]';
if (type.includes('()')) return 'jest.fn()';
return '{}';
if (type === "string") return "'test value'";
if (type === "number") return "42";
if (type === "boolean") return "true";
if (type.includes("[]")) return "[]";
if (type.includes("()")) return "jest.fn()";
return "{}";
}
}
```
@@ -345,7 +366,7 @@ const meta: Meta<typeof ${spec.name}> = {
component: ${spec.name},
tags: ['autodocs'],
argTypes: {
${spec.props.map(p => ` ${p.name}: { control: '${this.inferControl(p.type)}', description: '${p.description}' },`).join('\n')}
${spec.props.map((p) => ` ${p.name}: { control: '${this.inferControl(p.type)}', description: '${p.description}' },`).join("\n")}
},
};
@@ -354,7 +375,7 @@ type Story = StoryObj<typeof ${spec.name}>;
export const Default: Story = {
args: {
${spec.props.map(p => ` ${p.name}: ${p.defaultValue || this.getMockValue(p.type)},`).join('\n')}
${spec.props.map((p) => ` ${p.name}: ${p.defaultValue || this.getMockValue(p.type)},`).join("\n")}
},
};
@@ -367,11 +388,11 @@ export const Interactive: Story = {
}
inferControl(type: string): string {
if (type === 'string') return 'text';
if (type === 'number') return 'number';
if (type === 'boolean') return 'boolean';
if (type.includes('[]')) return 'object';
return 'text';
if (type === "string") return "text";
if (type === "number") return "number";
if (type === "boolean") return "boolean";
if (type.includes("[]")) return "object";
return "text";
}
}
```