@auto-engineer/design-system-importer 0.4.8 → 0.4.9

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.
@@ -1,6 +1,12 @@
1
1
  import { type CommandHandler, type Command, type Event } from '@auto-engineer/message-bus';
2
2
  import { importDesignSystemComponentsFromFigma, ImportStrategy, type FilterFunctionType } from '../index';
3
3
  import { FilterLoader } from '../utils/FilterLoader';
4
+ import createDebug from 'debug';
5
+
6
+ const debug = createDebug('design-system-importer:command');
7
+ const debugFilter = createDebug('design-system-importer:command:filter');
8
+ const debugHandler = createDebug('design-system-importer:command:handler');
9
+ const debugResult = createDebug('design-system-importer:command:result');
4
10
 
5
11
  export type ImportDesignSystemCommand = Command<
6
12
  'ImportDesignSystem',
@@ -27,31 +33,51 @@ export type DesignSystemImportFailedEvent = Event<
27
33
  >;
28
34
 
29
35
  // Handler
36
+ // eslint-disable-next-line complexity
30
37
  export async function handleImportDesignSystemCommand(
31
38
  command: ImportDesignSystemCommand,
32
39
  ): Promise<DesignSystemImportedEvent | DesignSystemImportFailedEvent> {
33
40
  const { outputDir, strategy, filterPath } = command.data;
34
41
 
42
+ debug('Handling ImportDesignSystemCommand');
43
+ debug(' Output directory: %s', outputDir);
44
+ debug(' Strategy: %s', strategy ?? 'default');
45
+ debug(' Filter path: %s', filterPath ?? 'none');
46
+ debug(' Request ID: %s', command.requestId);
47
+ debug(' Correlation ID: %s', command.correlationId ?? 'none');
48
+
35
49
  try {
36
50
  const resolvedStrategy = strategy ? ImportStrategy[strategy] : ImportStrategy.WITH_COMPONENT_SETS;
51
+ debugHandler('Resolved strategy: %s', resolvedStrategy);
37
52
 
38
53
  let filterFn: FilterFunctionType | undefined;
39
54
  let loader: FilterLoader | undefined;
40
55
  if (typeof filterPath === 'string' && filterPath.trim().length > 0) {
56
+ debugFilter('Loading custom filter from: %s', filterPath);
41
57
  try {
42
58
  loader = new FilterLoader();
59
+ debugFilter('FilterLoader instance created');
43
60
  filterFn = await loader.loadFilter(filterPath);
61
+ debugFilter('Filter function loaded successfully');
44
62
  } catch (e) {
63
+ debugFilter('ERROR: Failed to load filter from %s: %O', filterPath, e);
45
64
  console.warn(`Could not import filter from ${filterPath}. Skipping custom filter.`, e);
46
65
  } finally {
47
- if (loader) loader.cleanup();
66
+ if (loader) {
67
+ debugFilter('Cleaning up FilterLoader');
68
+ loader.cleanup();
69
+ }
48
70
  }
71
+ } else {
72
+ debugFilter('No filter path provided, proceeding without custom filter');
49
73
  }
50
74
 
75
+ debugHandler('Calling importDesignSystemComponentsFromFigma...');
51
76
  await importDesignSystemComponentsFromFigma(outputDir, resolvedStrategy, filterFn);
77
+ debugHandler('Import completed successfully');
52
78
  console.log(`Design system files processed to ${outputDir}`);
53
79
 
54
- return {
80
+ const successEvent: DesignSystemImportedEvent = {
55
81
  type: 'DesignSystemImported',
56
82
  data: {
57
83
  outputDir,
@@ -60,11 +86,16 @@ export async function handleImportDesignSystemCommand(
60
86
  requestId: command.requestId,
61
87
  correlationId: command.correlationId,
62
88
  };
89
+ debugResult('Returning success event: DesignSystemImported');
90
+ debugResult(' Output directory: %s', outputDir);
91
+ return successEvent;
63
92
  } catch (error) {
64
93
  const errorMessage = error instanceof Error ? error.message : String(error);
94
+ debugHandler('ERROR: Design system import failed: %O', error);
95
+ debugResult('Error message: %s', errorMessage);
65
96
  console.error('Error importing design system:', error);
66
97
 
67
- return {
98
+ const failureEvent: DesignSystemImportFailedEvent = {
68
99
  type: 'DesignSystemImportFailed',
69
100
  data: {
70
101
  error: errorMessage,
@@ -74,16 +105,23 @@ export async function handleImportDesignSystemCommand(
74
105
  requestId: command.requestId,
75
106
  correlationId: command.correlationId,
76
107
  };
108
+ debugResult('Returning failure event: DesignSystemImportFailed');
109
+ debugResult(' Error: %s', errorMessage);
110
+ debugResult(' Output directory: %s', outputDir);
111
+ return failureEvent;
77
112
  }
78
113
  }
79
114
 
80
115
  export const importDesignSystemCommandHandler: CommandHandler<ImportDesignSystemCommand> = {
81
116
  name: 'ImportDesignSystem',
82
117
  handle: async (command: ImportDesignSystemCommand): Promise<void> => {
118
+ debug('CommandHandler executing for ImportDesignSystem');
83
119
  const result = await handleImportDesignSystemCommand(command);
84
120
  if (result.type === 'DesignSystemImported') {
121
+ debug('Command handler completed: success');
85
122
  console.log('Design system imported successfully');
86
123
  } else {
124
+ debug('Command handler completed: failure - %s', result.data.error);
87
125
  console.error(`Failed: ${result.data.error}`);
88
126
  }
89
127
  },
package/src/index.ts CHANGED
@@ -4,53 +4,91 @@ import * as dotenv from 'dotenv';
4
4
  import { fileURLToPath } from 'url';
5
5
  import * as Figma from 'figma-api';
6
6
  import { FigmaComponentsBuilder, type FilterFunctionType } from './FigmaComponentsBuilder';
7
+ import createDebug from 'debug';
7
8
  // import { AIProvider, generateTextWithAI } from '@auto-engineer/ai-gateway';
8
9
 
10
+ const debug = createDebug('design-system-importer');
11
+ const debugFiles = createDebug('design-system-importer:files');
12
+ const debugFigma = createDebug('design-system-importer:figma');
13
+ const debugMarkdown = createDebug('design-system-importer:markdown');
14
+ const debugComponents = createDebug('design-system-importer:components');
15
+ const debugCopy = createDebug('design-system-importer:copy');
16
+
9
17
  dotenv.config();
18
+ debug('Design system importer initialized');
10
19
 
11
20
  const __filename = fileURLToPath(import.meta.url);
12
21
 
22
+ debugFigma('Initializing Figma API with personal access token');
13
23
  const api = new Figma.Api({
14
24
  personalAccessToken: process.env.FIGMA_PERSONAL_TOKEN as string,
15
25
  });
26
+ debugFigma('Figma API initialized');
16
27
 
17
28
  async function getAllTsxFiles(dir: string): Promise<string[]> {
29
+ debugFiles('Scanning directory for TSX files: %s', dir);
18
30
  let results: string[] = [];
19
- const entries = await fs.readdir(dir, { withFileTypes: true });
20
- for (const entry of entries) {
21
- const fullPath = path.join(dir, entry.name);
22
- if (entry.isDirectory()) {
23
- results = results.concat(await getAllTsxFiles(fullPath));
24
- } else if (entry.isFile() && entry.name.endsWith('.tsx')) {
25
- results.push(fullPath);
31
+
32
+ try {
33
+ const entries = await fs.readdir(dir, { withFileTypes: true });
34
+ debugFiles('Found %d entries in %s', entries.length, dir);
35
+
36
+ for (const entry of entries) {
37
+ const fullPath = path.join(dir, entry.name);
38
+ if (entry.isDirectory()) {
39
+ debugFiles('Entering subdirectory: %s', entry.name);
40
+ const subResults = await getAllTsxFiles(fullPath);
41
+ results = results.concat(subResults);
42
+ debugFiles('Found %d TSX files in %s', subResults.length, entry.name);
43
+ } else if (entry.isFile() && entry.name.endsWith('.tsx')) {
44
+ debugFiles('Found TSX file: %s', entry.name);
45
+ results.push(fullPath);
46
+ }
26
47
  }
48
+ } catch (error) {
49
+ debugFiles('Error reading directory %s: %O', dir, error);
27
50
  }
51
+
52
+ debugFiles('Total TSX files found in %s: %d', dir, results.length);
28
53
  return results;
29
54
  }
30
55
 
31
56
  function getComponentNameFromFile(filePath: string): string {
57
+ debugComponents('Extracting component name from: %s', filePath);
32
58
  const file = path.basename(filePath, '.tsx');
33
59
  // Capitalize first letter
34
- return file.charAt(0).toUpperCase() + file.slice(1);
60
+ const componentName = file.charAt(0).toUpperCase() + file.slice(1);
61
+ debugComponents('Component name: %s', componentName);
62
+ return componentName;
35
63
  }
36
64
 
37
65
  export async function generateDesignSystemMarkdown(inputDir: string, outputDir: string): Promise<void> {
66
+ debugMarkdown('Generating design system markdown from: %s to: %s', inputDir, outputDir);
67
+
38
68
  const files = await getAllTsxFiles(inputDir);
39
69
  if (files.length === 0) {
70
+ debugMarkdown('WARNING: No .tsx files found in input directory');
40
71
  console.warn('No .tsx files found in input directory.');
41
72
  return;
42
73
  }
43
74
 
75
+ debugMarkdown('Processing %d TSX files', files.length);
44
76
  const componentNames = files.map(getComponentNameFromFile).sort();
77
+ debugMarkdown('Found %d unique components', componentNames.length);
45
78
 
46
79
  let md = '# Design System\n\n## Components\n\n';
47
80
  for (const name of componentNames) {
48
81
  md += `- ${name}\n`;
82
+ debugMarkdown('Added component to markdown: %s', name);
49
83
  }
50
84
 
85
+ debugMarkdown('Creating output directory: %s', outputDir);
51
86
  await fs.mkdir(outputDir, { recursive: true });
87
+
52
88
  const outPath = path.join(outputDir, 'design-system.md');
89
+ debugMarkdown('Writing markdown to: %s', outPath);
53
90
  await fs.writeFile(outPath, md);
91
+ debugMarkdown('Markdown file written successfully, size: %d bytes', md.length);
54
92
  }
55
93
 
56
94
  export * from './commands/import-design-system';
@@ -59,65 +97,101 @@ export type { FilterFunctionType } from './FigmaComponentsBuilder';
59
97
  async function copyFile(inputDir: string, outputDir: string, file: string): Promise<void> {
60
98
  const srcPath = path.join(inputDir, file);
61
99
  const destPath = path.join(outputDir, file);
100
+ debugCopy('Attempting to copy file: %s from %s to %s', file, inputDir, outputDir);
62
101
 
63
102
  // Check if source file exists
64
103
  try {
65
104
  await fs.access(srcPath);
105
+ debugCopy('Source file exists: %s', srcPath);
106
+
107
+ debugCopy('Creating output directory: %s', outputDir);
66
108
  await fs.mkdir(outputDir, { recursive: true });
109
+
67
110
  await fs.copyFile(srcPath, destPath);
111
+ debugCopy('Successfully copied %s to %s', file, destPath);
68
112
  } catch (error) {
69
113
  // File doesn't exist, skip copying
114
+ debugCopy('File %s not found in %s, error: %O', file, inputDir, error);
70
115
  console.log(`File ${file} not found in ${inputDir}, skipping...`, error);
71
116
  }
72
117
  }
73
118
 
74
119
  export async function copyDesignSystemDocsAndUserPreferences(inputDir: string, outputDir: string): Promise<void> {
120
+ debugCopy('Copying design system docs from %s to %s', inputDir, outputDir);
121
+
75
122
  // Ensure output directory exists
123
+ debugCopy('Creating output directory: %s', outputDir);
76
124
  await fs.mkdir(outputDir, { recursive: true });
77
125
 
78
126
  // Try to copy existing files
127
+ debugCopy('Copying design-system.md...');
79
128
  await copyFile(inputDir, outputDir, 'design-system.md');
129
+
130
+ debugCopy('Copying design-system-principles.md...');
80
131
  await copyFile(inputDir, outputDir, 'design-system-principles.md');
81
132
 
82
133
  // If design-system.md doesn't exist in output, try to generate it from TSX files
83
134
  const designSystemPath = path.join(outputDir, 'design-system.md');
135
+ debugCopy('Checking if design-system.md exists at: %s', designSystemPath);
136
+
84
137
  try {
85
138
  await fs.access(designSystemPath);
139
+ debugCopy('design-system.md already exists');
86
140
  } catch {
141
+ debugCopy('design-system.md does not exist, attempting to generate from TSX files');
87
142
  // File doesn't exist, try to generate from TSX files if inputDir exists
88
143
  try {
89
144
  await fs.access(inputDir);
145
+ debugCopy('Input directory is accessible: %s', inputDir);
146
+
90
147
  const files = await getAllTsxFiles(inputDir);
91
148
  if (files.length > 0) {
149
+ debugCopy('Found %d TSX files, generating design-system.md', files.length);
92
150
  await generateDesignSystemMarkdown(inputDir, outputDir);
93
151
  console.log(`Generated design-system.md from ${files.length} component files`);
94
152
  } else {
153
+ debugCopy('No TSX files found in %s', inputDir);
95
154
  console.log(`No .tsx files found in ${inputDir} to generate design-system.md`);
96
155
  }
97
- } catch {
156
+ } catch (error) {
157
+ debugCopy('Input directory %s not accessible: %O', inputDir, error);
98
158
  console.log(`Input directory ${inputDir} not accessible`);
99
159
  }
100
160
  }
161
+
162
+ debugCopy('Design system docs copy/generation complete');
101
163
  }
102
164
 
103
165
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
104
166
  async function getFigmaComponents(): Promise<{ name: string; description: string; thumbnail: string }[]> {
167
+ debugFigma('Fetching Figma components from file: %s', process.env.FIGMA_FILE_ID);
105
168
  let components: { name: string; description: string; thumbnail: string }[] = [];
169
+
106
170
  try {
171
+ debugFigma('Making API call to Figma...');
107
172
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
108
173
  const response = await api.getFileComponentSets({ file_key: process.env.FIGMA_FILE_ID });
174
+ debugFigma('Figma API response received');
175
+
109
176
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
110
177
  components = response.meta.component_sets.map(
111
- (component: { name: string; description: string; thumbnail_url: string }) => ({
112
- name: component.name,
113
- description: component.description,
114
- thumbnail: component.thumbnail_url,
115
- }),
178
+ (component: { name: string; description: string; thumbnail_url: string }) => {
179
+ debugFigma('Processing component: %s', component.name);
180
+ return {
181
+ name: component.name,
182
+ description: component.description,
183
+ thumbnail: component.thumbnail_url,
184
+ };
185
+ },
116
186
  );
187
+
188
+ debugFigma('Successfully fetched %d components from Figma', components.length);
117
189
  console.log('figma response: ', response);
118
190
  } catch (e) {
191
+ debugFigma('ERROR: Failed to fetch Figma components: %O', e);
119
192
  console.error(e);
120
193
  }
194
+
121
195
  console.log(components.length);
122
196
  return components;
123
197
  }
@@ -125,16 +199,21 @@ async function getFigmaComponents(): Promise<{ name: string; description: string
125
199
  export function generateMarkdownFromComponents(
126
200
  components: { name: string; description: string; thumbnail: string }[],
127
201
  ): string {
202
+ debugMarkdown('Generating markdown from %d components', components.length);
128
203
  let md = '# Design System\n\n## Components\n\n';
129
204
 
130
205
  if (components.length === 0) {
206
+ debugMarkdown('WARNING: No components found to generate markdown');
131
207
  console.warn('No components found');
132
208
  }
133
209
 
134
- for (const component of components) {
210
+ for (const [index, component] of components.entries()) {
211
+ debugMarkdown('Processing component %d/%d: %s', index + 1, components.length, component.name);
135
212
  md += `### ${component.name}\nDescription: ${component.description}\nImage: ![${component.name} image](${component.thumbnail})\n\n`;
213
+ debugMarkdown('Added component %s with description length: %d', component.name, component.description.length);
136
214
  }
137
215
 
216
+ debugMarkdown('Generated markdown document, total size: %d bytes', md.length);
138
217
  return md;
139
218
  }
140
219
 
@@ -149,28 +228,44 @@ export async function importDesignSystemComponentsFromFigma(
149
228
  strategy: ImportStrategy = ImportStrategy.WITH_COMPONENT_SETS,
150
229
  filterFn?: FilterFunctionType,
151
230
  ): Promise<void> {
231
+ debug('Starting Figma design system import');
232
+ debug('Output directory: %s', outputDir);
233
+ debug('Import strategy: %s', strategy);
234
+ debug('Filter function provided: %s', filterFn ? 'yes' : 'no');
235
+
152
236
  const figmaComponentsBuilder = new FigmaComponentsBuilder();
237
+ debugComponents('FigmaComponentsBuilder instance created');
153
238
 
154
239
  if (strategy === ImportStrategy.WITH_COMPONENTS) {
240
+ debugComponents('Using strategy: WITH_COMPONENTS');
155
241
  await figmaComponentsBuilder.withFigmaComponents();
156
242
  } else if (strategy === ImportStrategy.WITH_COMPONENT_SETS) {
243
+ debugComponents('Using strategy: WITH_COMPONENT_SETS');
157
244
  await figmaComponentsBuilder.withFigmaComponentSets();
158
245
  } else if (strategy === ImportStrategy.WITH_ALL_FIGMA_INSTANCES) {
246
+ debugComponents('Using strategy: WITH_ALL_FIGMA_INSTANCES');
159
247
  await figmaComponentsBuilder.withAllFigmaInstanceNames();
160
248
  }
249
+ debugComponents('Strategy applied successfully');
161
250
 
162
251
  // figmaComponentsBuilder.withFilteredNamesForMui();
163
252
  // figmaComponentsBuilder.withFilteredNamesForShadcn();
164
253
 
165
254
  if (filterFn) {
255
+ debugComponents('Applying custom filter function');
166
256
  figmaComponentsBuilder.withFilter(filterFn);
167
257
  }
168
258
 
259
+ debugComponents('Building Figma components...');
169
260
  const figmaComponents = figmaComponentsBuilder.build();
261
+ debugComponents('Built %d Figma components', figmaComponents.length);
170
262
 
171
263
  console.log(figmaComponents.length);
172
264
 
265
+ debugMarkdown('Generating markdown from Figma components');
173
266
  const generatedComponentsMDFile = generateMarkdownFromComponents(figmaComponents);
267
+ debugMarkdown('Markdown generated, size: %d bytes', generatedComponentsMDFile.length);
268
+
174
269
  // const mdWithImageAnalysis = await generateTextWithAI(
175
270
  // `
176
271
  // Given this markdown file content:
@@ -186,8 +281,16 @@ export async function importDesignSystemComponentsFromFigma(
186
281
  // { temperature: 0.2, maxTokens: 8000 },
187
282
  // );
188
283
  // await fs.mkdir(outputDir, { recursive: true });
284
+
285
+ debugFiles('Creating output directory: %s', outputDir);
286
+ await fs.mkdir(outputDir, { recursive: true });
287
+
189
288
  const outPath = path.join(outputDir, 'design-system.md');
289
+ debugFiles('Writing markdown to: %s', outPath);
190
290
  await fs.writeFile(outPath, generatedComponentsMDFile);
291
+ debugFiles('Design system markdown written successfully');
292
+
293
+ debug('Figma design system import complete');
191
294
  }
192
295
 
193
296
  // Check if this file is being run directly