@auto-engineer/component-implementor-react 1.110.0 → 1.110.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-test.log +3 -3
  3. package/.turbo/turbo-type-check.log +1 -1
  4. package/CHANGELOG.md +13 -0
  5. package/dist/src/commands/implement-component.d.ts.map +1 -1
  6. package/dist/src/commands/implement-component.js +5 -1
  7. package/dist/src/commands/implement-component.js.map +1 -1
  8. package/dist/src/index.d.ts +0 -1
  9. package/dist/src/index.d.ts.map +1 -1
  10. package/dist/src/index.js +0 -1
  11. package/dist/src/index.js.map +1 -1
  12. package/dist/src/pipeline/run-pipeline.d.ts +4 -3
  13. package/dist/src/pipeline/run-pipeline.d.ts.map +1 -1
  14. package/dist/src/pipeline/run-pipeline.js +2 -2
  15. package/dist/src/pipeline/run-pipeline.js.map +1 -1
  16. package/dist/src/pipeline/run-pipeline.test.js +4 -2
  17. package/dist/src/pipeline/run-pipeline.test.js.map +1 -1
  18. package/dist/src/pipeline/steps/generate-story.d.ts +2 -1
  19. package/dist/src/pipeline/steps/generate-story.d.ts.map +1 -1
  20. package/dist/src/pipeline/steps/generate-story.js +11 -5
  21. package/dist/src/pipeline/steps/generate-story.js.map +1 -1
  22. package/dist/src/pipeline/steps/generate-story.test.js +11 -5
  23. package/dist/src/pipeline/steps/generate-story.test.js.map +1 -1
  24. package/dist/tsconfig.tsbuildinfo +1 -1
  25. package/package.json +3 -3
  26. package/src/commands/implement-component.ts +6 -1
  27. package/src/index.ts +0 -1
  28. package/src/pipeline/run-pipeline.test.ts +4 -2
  29. package/src/pipeline/run-pipeline.ts +6 -5
  30. package/src/pipeline/steps/generate-story.test.ts +14 -5
  31. package/src/pipeline/steps/generate-story.ts +13 -5
  32. package/vitest.config.ts +1 -1
  33. package/dist/src/generate-story-deterministic.d.ts +0 -30
  34. package/dist/src/generate-story-deterministic.d.ts.map +0 -1
  35. package/dist/src/generate-story-deterministic.js +0 -229
  36. package/dist/src/generate-story-deterministic.js.map +0 -1
  37. package/src/generate-story-deterministic.ts +0 -267
@@ -1,267 +0,0 @@
1
- // ═══════════════════════════════════════════════════════════════════
2
- // Deterministic story generator — no LLM call, pure template logic
3
- // ═══════════════════════════════════════════════════════════════════
4
-
5
- export interface DeterministicStoryProp {
6
- name: string;
7
- type: string;
8
- required: boolean;
9
- default?: string;
10
- description: string;
11
- category: 'data' | 'callback' | 'slot' | 'visual' | 'state' | 'config';
12
- }
13
-
14
- export interface StoryVariant {
15
- name: string;
16
- description: string;
17
- args: Record<string, unknown>;
18
- needsPlayFunction?: boolean;
19
- playDescription?: string;
20
- }
21
-
22
- export interface DeterministicStoryInput {
23
- componentName: string;
24
- componentImportPath: string;
25
- props?: DeterministicStoryProp[];
26
- storyVariants?: StoryVariant[];
27
- }
28
-
29
- /**
30
- * Generates a Storybook CSF3 story file deterministically (no LLM call).
31
- *
32
- * Uses structured prop data and optional story variants to emit a complete
33
- * `.stories.tsx` file string. When no variants are provided, a Default
34
- * story is synthesized from the props with sensible placeholder values.
35
- */
36
- export function generateStoryDeterministic(input: DeterministicStoryInput): string {
37
- const { componentName, componentImportPath, props, storyVariants } = input;
38
-
39
- const lines: string[] = [];
40
-
41
- // ── Imports ──────────────────────────────────────────────────────
42
- lines.push(`import type { Meta, StoryObj } from '@storybook/react-vite';`);
43
- lines.push(`import { ${componentName} } from '${componentImportPath}';`);
44
- lines.push('');
45
-
46
- // ── Meta ─────────────────────────────────────────────────────────
47
- lines.push(`const meta: Meta<typeof ${componentName}> = {`);
48
- lines.push(` title: 'UI Components/${componentName}',`);
49
- lines.push(` component: ${componentName},`);
50
- lines.push(`};`);
51
- lines.push(`export default meta;`);
52
- lines.push('');
53
-
54
- // ── Story type alias ─────────────────────────────────────────────
55
- lines.push(`type Story = StoryObj<typeof ${componentName}>;`);
56
-
57
- // ── Stories ──────────────────────────────────────────────────────
58
- if (storyVariants && storyVariants.length > 0) {
59
- for (const variant of storyVariants) {
60
- lines.push('');
61
- lines.push(`export const ${variant.name}: Story = {`);
62
- const argsBlock = serializeArgs(variant.args);
63
- if (argsBlock) {
64
- lines.push(` args: {`);
65
- lines.push(argsBlock);
66
- lines.push(` },`);
67
- }
68
- lines.push(`};`);
69
- }
70
- } else {
71
- // Derive a Default story from props
72
- const defaultArgs = deriveDefaultArgs(props ?? []);
73
- lines.push('');
74
- lines.push(`export const Default: Story = {`);
75
- const argsBlock = serializeArgs(defaultArgs);
76
- if (argsBlock) {
77
- lines.push(` args: {`);
78
- lines.push(argsBlock);
79
- lines.push(` },`);
80
- }
81
- lines.push(`};`);
82
- }
83
-
84
- lines.push('');
85
- return lines.join('\n');
86
- }
87
-
88
- // ═══════════════════════════════════════════════════════════════════
89
- // Internals
90
- // ═══════════════════════════════════════════════════════════════════
91
-
92
- /**
93
- * Derives sensible default arg values from structured prop definitions.
94
- *
95
- * - `callback` props are omitted (Storybook auto-detects them via argTypes).
96
- * - `slot` props are omitted (ReactNode cannot be serialized to args).
97
- * - `data` props get placeholder values based on their TypeScript type.
98
- * - `visual` props use the declared default if present, otherwise a placeholder.
99
- * - `state` props default to `false`.
100
- * - `config` props use the declared default if present, otherwise a placeholder.
101
- */
102
- function deriveDefaultArgs(props: DeterministicStoryProp[]): Record<string, unknown> {
103
- const args: Record<string, unknown> = {};
104
-
105
- for (const prop of props) {
106
- // Skip categories that cannot or should not be serialized in args
107
- if (prop.category === 'callback' || prop.category === 'slot') {
108
- continue;
109
- }
110
-
111
- if (prop.category === 'state') {
112
- args[prop.name] = false;
113
- continue;
114
- }
115
-
116
- // If a default is declared, try to use it
117
- if (prop.default !== undefined) {
118
- const parsed = parseDefaultValue(prop.default);
119
- if (parsed !== undefined) {
120
- args[prop.name] = parsed;
121
- continue;
122
- }
123
- }
124
-
125
- // Otherwise generate a placeholder based on the TypeScript type string
126
- args[prop.name] = placeholderForType(prop.type);
127
- }
128
-
129
- return args;
130
- }
131
-
132
- /**
133
- * Attempts to parse a default value string into a JS primitive.
134
- * Returns `undefined` when the string cannot be meaningfully parsed
135
- * (e.g. an arrow function or complex expression).
136
- */
137
- function parseDefaultValue(raw: string): unknown {
138
- const trimmed = raw.trim();
139
- if (trimmed === 'true') return true;
140
- if (trimmed === 'false') return false;
141
- if (trimmed === 'null') return null;
142
- if (trimmed === 'undefined') return undefined;
143
-
144
- // Quoted string
145
- const stringMatch = trimmed.match(/^['"](.*)['"]$/);
146
- if (stringMatch) return stringMatch[1];
147
-
148
- // Numeric
149
- const num = Number(trimmed);
150
- if (!Number.isNaN(num) && trimmed !== '') return num;
151
-
152
- // Array or object literal — attempt JSON parse
153
- if (trimmed.startsWith('[') || trimmed.startsWith('{')) {
154
- try {
155
- return JSON.parse(trimmed);
156
- } catch {
157
- return undefined;
158
- }
159
- }
160
-
161
- // Anything else (functions, expressions) → skip
162
- return undefined;
163
- }
164
-
165
- /**
166
- * Returns a sensible placeholder value for a given TypeScript type string.
167
- */
168
- function placeholderForType(typeStr: string): unknown {
169
- const t = typeStr.trim();
170
-
171
- if (t === 'string') return 'Example';
172
- if (t === 'number') return 42;
173
- if (t === 'boolean') return true;
174
-
175
- // Union of string literals — pick the first literal
176
- const literalUnion = t.match(/^['"]([^'"]+)['"]/);
177
- if (literalUnion) return literalUnion[1];
178
-
179
- // Array types
180
- if (t.endsWith('[]') || t.startsWith('Array<')) return [];
181
-
182
- // Generic object / Record
183
- if (t === 'object' || t.startsWith('Record<') || t.startsWith('{')) return {};
184
-
185
- // Fallback
186
- return undefined;
187
- }
188
-
189
- /**
190
- * Serializes an args record into indented TypeScript object body lines.
191
- * Returns an empty string when the args record is empty (caller should
192
- * omit the `args` block entirely).
193
- *
194
- * Each value is formatted as a valid TypeScript literal:
195
- * - strings → quoted
196
- * - numbers / booleans → as-is
197
- * - arrays / plain objects → JSON.stringify
198
- * - undefined, null, functions → skipped
199
- */
200
- function serializeArgs(args: Record<string, unknown>): string {
201
- const entries: string[] = [];
202
-
203
- for (const [key, value] of Object.entries(args)) {
204
- const formatted = formatArgValue(value);
205
- if (formatted === null) continue;
206
- entries.push(` ${key}: ${formatted},`);
207
- }
208
-
209
- return entries.join('\n');
210
- }
211
-
212
- function formatArgValue(value: unknown): string | null {
213
- if (value === undefined) return null;
214
- if (value === null) return null;
215
- if (typeof value === 'function') return null;
216
-
217
- if (typeof value === 'string') {
218
- // Callback strings like "() => {}" — emit as raw JS, not quoted
219
- if (/^\s*\(/.test(value) || /^\s*function\s*\(/.test(value)) {
220
- return value;
221
- }
222
- return JSON.stringify(value);
223
- }
224
- if (typeof value === 'number') return String(value);
225
- if (typeof value === 'boolean') return String(value);
226
-
227
- // Arrays and plain objects — deep-fix stringified JSON values first
228
- if (Array.isArray(value) || typeof value === 'object') {
229
- const fixed = deepParseStringifiedJson(value);
230
- return JSON.stringify(fixed);
231
- }
232
-
233
- return null;
234
- }
235
-
236
- /**
237
- * Recursively walks a value and parses any string that looks like
238
- * stringified JSON back into an actual object/array. This fixes
239
- * FEA output where nested objects are accidentally double-stringified.
240
- */
241
- function deepParseStringifiedJson(value: unknown): unknown {
242
- if (typeof value === 'string') {
243
- const trimmed = value.trim();
244
- if ((trimmed.startsWith('{') && trimmed.endsWith('}')) || (trimmed.startsWith('[') && trimmed.endsWith(']'))) {
245
- try {
246
- return deepParseStringifiedJson(JSON.parse(trimmed));
247
- } catch {
248
- return value;
249
- }
250
- }
251
- return value;
252
- }
253
-
254
- if (Array.isArray(value)) {
255
- return value.map(deepParseStringifiedJson);
256
- }
257
-
258
- if (value !== null && typeof value === 'object') {
259
- const result: Record<string, unknown> = {};
260
- for (const [k, v] of Object.entries(value)) {
261
- result[k] = deepParseStringifiedJson(v);
262
- }
263
- return result;
264
- }
265
-
266
- return value;
267
- }