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

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.
package/src/index.ts CHANGED
@@ -4,120 +4,195 @@ 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';
57
95
  export type { FilterFunctionType } from './FigmaComponentsBuilder';
96
+ export { CLI_MANIFEST } from './cli-manifest';
58
97
 
59
98
  async function copyFile(inputDir: string, outputDir: string, file: string): Promise<void> {
60
99
  const srcPath = path.join(inputDir, file);
61
100
  const destPath = path.join(outputDir, file);
101
+ debugCopy('Attempting to copy file: %s from %s to %s', file, inputDir, outputDir);
62
102
 
63
103
  // Check if source file exists
64
104
  try {
65
105
  await fs.access(srcPath);
106
+ debugCopy('Source file exists: %s', srcPath);
107
+
108
+ debugCopy('Creating output directory: %s', outputDir);
66
109
  await fs.mkdir(outputDir, { recursive: true });
110
+
67
111
  await fs.copyFile(srcPath, destPath);
112
+ debugCopy('Successfully copied %s to %s', file, destPath);
68
113
  } catch (error) {
69
114
  // File doesn't exist, skip copying
115
+ debugCopy('File %s not found in %s, error: %O', file, inputDir, error);
70
116
  console.log(`File ${file} not found in ${inputDir}, skipping...`, error);
71
117
  }
72
118
  }
73
119
 
74
120
  export async function copyDesignSystemDocsAndUserPreferences(inputDir: string, outputDir: string): Promise<void> {
121
+ debugCopy('Copying design system docs from %s to %s', inputDir, outputDir);
122
+
75
123
  // Ensure output directory exists
124
+ debugCopy('Creating output directory: %s', outputDir);
76
125
  await fs.mkdir(outputDir, { recursive: true });
77
126
 
78
127
  // Try to copy existing files
128
+ debugCopy('Copying design-system.md...');
79
129
  await copyFile(inputDir, outputDir, 'design-system.md');
130
+
131
+ debugCopy('Copying design-system-principles.md...');
80
132
  await copyFile(inputDir, outputDir, 'design-system-principles.md');
81
133
 
82
134
  // If design-system.md doesn't exist in output, try to generate it from TSX files
83
135
  const designSystemPath = path.join(outputDir, 'design-system.md');
136
+ debugCopy('Checking if design-system.md exists at: %s', designSystemPath);
137
+
84
138
  try {
85
139
  await fs.access(designSystemPath);
140
+ debugCopy('design-system.md already exists');
86
141
  } catch {
142
+ debugCopy('design-system.md does not exist, attempting to generate from TSX files');
87
143
  // File doesn't exist, try to generate from TSX files if inputDir exists
88
144
  try {
89
145
  await fs.access(inputDir);
146
+ debugCopy('Input directory is accessible: %s', inputDir);
147
+
90
148
  const files = await getAllTsxFiles(inputDir);
91
149
  if (files.length > 0) {
150
+ debugCopy('Found %d TSX files, generating design-system.md', files.length);
92
151
  await generateDesignSystemMarkdown(inputDir, outputDir);
93
152
  console.log(`Generated design-system.md from ${files.length} component files`);
94
153
  } else {
154
+ debugCopy('No TSX files found in %s', inputDir);
95
155
  console.log(`No .tsx files found in ${inputDir} to generate design-system.md`);
96
156
  }
97
- } catch {
157
+ } catch (error) {
158
+ debugCopy('Input directory %s not accessible: %O', inputDir, error);
98
159
  console.log(`Input directory ${inputDir} not accessible`);
99
160
  }
100
161
  }
162
+
163
+ debugCopy('Design system docs copy/generation complete');
101
164
  }
102
165
 
103
166
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
104
167
  async function getFigmaComponents(): Promise<{ name: string; description: string; thumbnail: string }[]> {
168
+ debugFigma('Fetching Figma components from file: %s', process.env.FIGMA_FILE_ID);
105
169
  let components: { name: string; description: string; thumbnail: string }[] = [];
170
+
106
171
  try {
172
+ debugFigma('Making API call to Figma...');
107
173
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
108
174
  const response = await api.getFileComponentSets({ file_key: process.env.FIGMA_FILE_ID });
175
+ debugFigma('Figma API response received');
176
+
109
177
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
110
178
  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
- }),
179
+ (component: { name: string; description: string; thumbnail_url: string }) => {
180
+ debugFigma('Processing component: %s', component.name);
181
+ return {
182
+ name: component.name,
183
+ description: component.description,
184
+ thumbnail: component.thumbnail_url,
185
+ };
186
+ },
116
187
  );
188
+
189
+ debugFigma('Successfully fetched %d components from Figma', components.length);
117
190
  console.log('figma response: ', response);
118
191
  } catch (e) {
192
+ debugFigma('ERROR: Failed to fetch Figma components: %O', e);
119
193
  console.error(e);
120
194
  }
195
+
121
196
  console.log(components.length);
122
197
  return components;
123
198
  }
@@ -125,16 +200,21 @@ async function getFigmaComponents(): Promise<{ name: string; description: string
125
200
  export function generateMarkdownFromComponents(
126
201
  components: { name: string; description: string; thumbnail: string }[],
127
202
  ): string {
203
+ debugMarkdown('Generating markdown from %d components', components.length);
128
204
  let md = '# Design System\n\n## Components\n\n';
129
205
 
130
206
  if (components.length === 0) {
207
+ debugMarkdown('WARNING: No components found to generate markdown');
131
208
  console.warn('No components found');
132
209
  }
133
210
 
134
- for (const component of components) {
211
+ for (const [index, component] of components.entries()) {
212
+ debugMarkdown('Processing component %d/%d: %s', index + 1, components.length, component.name);
135
213
  md += `### ${component.name}\nDescription: ${component.description}\nImage: ![${component.name} image](${component.thumbnail})\n\n`;
214
+ debugMarkdown('Added component %s with description length: %d', component.name, component.description.length);
136
215
  }
137
216
 
217
+ debugMarkdown('Generated markdown document, total size: %d bytes', md.length);
138
218
  return md;
139
219
  }
140
220
 
@@ -149,28 +229,44 @@ export async function importDesignSystemComponentsFromFigma(
149
229
  strategy: ImportStrategy = ImportStrategy.WITH_COMPONENT_SETS,
150
230
  filterFn?: FilterFunctionType,
151
231
  ): Promise<void> {
232
+ debug('Starting Figma design system import');
233
+ debug('Output directory: %s', outputDir);
234
+ debug('Import strategy: %s', strategy);
235
+ debug('Filter function provided: %s', filterFn ? 'yes' : 'no');
236
+
152
237
  const figmaComponentsBuilder = new FigmaComponentsBuilder();
238
+ debugComponents('FigmaComponentsBuilder instance created');
153
239
 
154
240
  if (strategy === ImportStrategy.WITH_COMPONENTS) {
241
+ debugComponents('Using strategy: WITH_COMPONENTS');
155
242
  await figmaComponentsBuilder.withFigmaComponents();
156
243
  } else if (strategy === ImportStrategy.WITH_COMPONENT_SETS) {
244
+ debugComponents('Using strategy: WITH_COMPONENT_SETS');
157
245
  await figmaComponentsBuilder.withFigmaComponentSets();
158
246
  } else if (strategy === ImportStrategy.WITH_ALL_FIGMA_INSTANCES) {
247
+ debugComponents('Using strategy: WITH_ALL_FIGMA_INSTANCES');
159
248
  await figmaComponentsBuilder.withAllFigmaInstanceNames();
160
249
  }
250
+ debugComponents('Strategy applied successfully');
161
251
 
162
252
  // figmaComponentsBuilder.withFilteredNamesForMui();
163
253
  // figmaComponentsBuilder.withFilteredNamesForShadcn();
164
254
 
165
255
  if (filterFn) {
256
+ debugComponents('Applying custom filter function');
166
257
  figmaComponentsBuilder.withFilter(filterFn);
167
258
  }
168
259
 
260
+ debugComponents('Building Figma components...');
169
261
  const figmaComponents = figmaComponentsBuilder.build();
262
+ debugComponents('Built %d Figma components', figmaComponents.length);
170
263
 
171
264
  console.log(figmaComponents.length);
172
265
 
266
+ debugMarkdown('Generating markdown from Figma components');
173
267
  const generatedComponentsMDFile = generateMarkdownFromComponents(figmaComponents);
268
+ debugMarkdown('Markdown generated, size: %d bytes', generatedComponentsMDFile.length);
269
+
174
270
  // const mdWithImageAnalysis = await generateTextWithAI(
175
271
  // `
176
272
  // Given this markdown file content:
@@ -186,8 +282,21 @@ export async function importDesignSystemComponentsFromFigma(
186
282
  // { temperature: 0.2, maxTokens: 8000 },
187
283
  // );
188
284
  // await fs.mkdir(outputDir, { recursive: true });
189
- const outPath = path.join(outputDir, 'design-system.md');
285
+
286
+ // Parse the outputDir to determine if it's a file path or directory
287
+ const isFilePath = outputDir.endsWith('.md');
288
+ const actualOutputDir = isFilePath ? path.dirname(outputDir) : outputDir;
289
+ const fileName = isFilePath ? path.basename(outputDir) : 'design-system.md';
290
+
291
+ debugFiles('Creating output directory: %s', actualOutputDir);
292
+ await fs.mkdir(actualOutputDir, { recursive: true });
293
+
294
+ const outPath = path.join(actualOutputDir, fileName);
295
+ debugFiles('Writing markdown to: %s', outPath);
190
296
  await fs.writeFile(outPath, generatedComponentsMDFile);
297
+ debugFiles('Design system markdown written successfully');
298
+
299
+ debug('Figma design system import complete');
191
300
  }
192
301
 
193
302
  // Check if this file is being run directly
@@ -4,57 +4,83 @@ import { existsSync, readFileSync, writeFileSync, mkdtempSync, rmSync } from 'fs
4
4
  import { spawnSync } from 'child_process';
5
5
  import { tmpdir } from 'os';
6
6
  import type { FilterFunctionType } from '../FigmaComponentsBuilder';
7
+ import createDebug from 'debug';
8
+
9
+ const debug = createDebug('design-system-importer:filter-loader');
10
+ const debugLoad = createDebug('design-system-importer:filter-loader:load');
11
+ const debugTS = createDebug('design-system-importer:filter-loader:typescript');
12
+ const debugStrategy = createDebug('design-system-importer:filter-loader:strategy');
13
+ const debugTemplate = createDebug('design-system-importer:filter-loader:template');
7
14
 
8
15
  export class FilterLoader {
9
16
  private templatesDir: string;
10
17
 
11
18
  constructor() {
19
+ debug('FilterLoader instance created');
12
20
  // Get the directory where template files are stored
13
21
  const currentFile = fileURLToPath(import.meta.url);
14
22
  this.templatesDir = join(dirname(currentFile), 'templates');
23
+ debug('Templates directory: %s', this.templatesDir);
15
24
  }
16
25
 
17
26
  async loadFilter(filePath: string): Promise<FilterFunctionType> {
27
+ debugLoad('Loading filter from: %s', filePath);
28
+
18
29
  if (typeof filePath !== 'string' || filePath.trim().length === 0) {
30
+ debugLoad('ERROR: Invalid filter path provided');
19
31
  throw new Error('Filter file path is required');
20
32
  }
21
33
 
22
34
  const absolutePath = resolvePath(process.cwd(), filePath);
35
+ debugLoad('Resolved absolute path: %s', absolutePath);
23
36
 
24
37
  if (!existsSync(absolutePath)) {
38
+ debugLoad('ERROR: Filter file not found at %s', absolutePath);
25
39
  throw new Error(`Filter file not found: ${absolutePath}`);
26
40
  }
27
41
 
28
42
  const ext = extname(absolutePath).toLowerCase();
43
+ debugLoad('File extension: %s', ext);
29
44
 
30
45
  // For TypeScript files, use tsx to load them
31
46
  if (ext === '.ts' || ext === '.tsx') {
47
+ debugLoad('Detected TypeScript file, using TypeScript loader');
32
48
  return this.loadTypeScriptFilter(absolutePath);
33
49
  }
34
50
 
35
51
  // For JavaScript files, load directly
52
+ debugLoad('Loading JavaScript file directly');
36
53
  const fileUrl = pathToFileURL(absolutePath).href;
54
+ debugLoad('File URL: %s', fileUrl);
55
+
37
56
  const loadedUnknown: unknown = await import(fileUrl);
38
57
  const loadedModule = loadedUnknown as { filter?: unknown; default?: unknown };
58
+ debugLoad('Module loaded, checking for filter function');
39
59
 
40
60
  if (typeof loadedModule.filter === 'function') {
61
+ debugLoad('Found named export "filter"');
41
62
  return loadedModule.filter as FilterFunctionType;
42
63
  }
43
64
 
44
65
  if (typeof loadedModule.default === 'function') {
66
+ debugLoad('Found default export, using as filter');
45
67
  console.warn('Using default export from filter module. Prefer a named export "filter".');
46
68
  return loadedModule.default as FilterFunctionType;
47
69
  }
48
70
 
71
+ debugLoad('ERROR: No filter function found in module');
49
72
  throw new Error('No filter function found. Export a function named "filter" or as a default export from the file.');
50
73
  }
51
74
 
52
75
  private async loadTypeScriptFilter(filePath: string): Promise<FilterFunctionType> {
76
+ debugTS('Loading TypeScript filter from: %s', filePath);
53
77
  // Create a temporary directory for our scripts
54
78
  const tempDir = mkdtempSync(join(tmpdir(), 'tsx-filter-'));
79
+ debugTS('Created temp directory: %s', tempDir);
55
80
 
56
81
  try {
57
82
  const filterUrl = pathToFileURL(filePath).href;
83
+ debugTS('Filter URL: %s', filterUrl);
58
84
 
59
85
  // Try different loading strategies in order
60
86
  const strategies = [
@@ -62,14 +88,19 @@ export class FilterLoader {
62
88
  () => this.tryNpxTsxExport(tempDir, filterUrl),
63
89
  () => this.tryNodeLoaderOptions(tempDir, filterUrl),
64
90
  ];
91
+ debugTS('Will try %d loading strategies', strategies.length);
65
92
 
66
- for (const strategy of strategies) {
67
- const result = await strategy();
93
+ for (let i = 0; i < strategies.length; i++) {
94
+ debugTS('Trying strategy %d/%d', i + 1, strategies.length);
95
+ const result = await strategies[i]();
68
96
  if (result) {
97
+ debugTS('Strategy %d succeeded!', i + 1);
69
98
  return result;
70
99
  }
100
+ debugTS('Strategy %d failed, trying next...', i + 1);
71
101
  }
72
102
 
103
+ debugTS('ERROR: All strategies failed to load TypeScript filter');
73
104
  throw new Error(
74
105
  `TypeScript filter cannot be loaded. ` +
75
106
  `Please ensure tsx is installed in your project:\n` +
@@ -77,25 +108,32 @@ export class FilterLoader {
77
108
  `Or provide a JavaScript version of your filter.`,
78
109
  );
79
110
  } catch (error) {
111
+ debugTS('ERROR: Failed to load TypeScript filter: %O', error);
80
112
  throw new Error(
81
113
  `Failed to load TypeScript filter.\n` +
82
114
  `Error: ${error instanceof Error ? error.message : String(error)}\n` +
83
115
  `Please ensure tsx is installed locally: npm install -D tsx`,
84
116
  );
85
117
  } finally {
118
+ debugTS('Cleaning up temp directory: %s', tempDir);
86
119
  // Clean up temp files
87
120
  try {
88
121
  rmSync(tempDir, { recursive: true, force: true });
89
- } catch {
122
+ debugTS('Temp directory cleaned up successfully');
123
+ } catch (cleanupError) {
124
+ debugTS('Warning: Failed to clean up temp directory: %O', cleanupError);
90
125
  // Ignore cleanup errors
91
126
  }
92
127
  }
93
128
  }
94
129
 
95
130
  private async tryNodeDirectLoad(tempDir: string, filterUrl: string): Promise<FilterFunctionType | null> {
131
+ debugStrategy('Strategy: Node direct load');
96
132
  // First attempt: Try to run the loader script with Node.js directly
97
133
  const loaderFile = this.prepareTemplate(tempDir, 'tsx-loader.mjs', filterUrl);
134
+ debugStrategy('Prepared loader file: %s', loaderFile);
98
135
 
136
+ debugStrategy('Spawning node with experimental loader...');
99
137
  const result = spawnSync('node', [loaderFile], {
100
138
  cwd: process.cwd(),
101
139
  encoding: 'utf-8',
@@ -104,46 +142,69 @@ export class FilterLoader {
104
142
  NODE_OPTIONS: '--experimental-loader tsx',
105
143
  },
106
144
  });
145
+ debugStrategy('Node process exit code: %d', result.status);
107
146
 
108
147
  if (result.status === 0) {
148
+ debugStrategy('Node direct load succeeded, importing module');
109
149
  // Success! Now import the loader module to get the filter
110
150
  const loaderModule = (await import(pathToFileURL(loaderFile).href)) as { filter: FilterFunctionType };
151
+ debugStrategy('Filter function retrieved from module');
111
152
  return loaderModule.filter;
112
153
  }
113
154
 
155
+ debugStrategy('Node direct load failed');
156
+ if (result.stderr) {
157
+ debugStrategy('Error output: %s', result.stderr);
158
+ }
114
159
  return null;
115
160
  }
116
161
 
117
162
  private async tryNpxTsxExport(tempDir: string, filterUrl: string): Promise<FilterFunctionType | null> {
163
+ debugStrategy('Strategy: npx tsx export');
118
164
  // Second attempt: Use npx tsx to run a script that exports the filter
119
165
  const exportFile = this.prepareTemplate(tempDir, 'tsx-export.mjs', filterUrl);
166
+ debugStrategy('Prepared export file: %s', exportFile);
120
167
 
168
+ debugStrategy('Spawning npx tsx...');
121
169
  const npxResult = spawnSync('npx', ['tsx', exportFile], {
122
170
  cwd: process.cwd(),
123
171
  encoding: 'utf-8',
124
172
  shell: true,
125
173
  });
174
+ debugStrategy('npx process exit code: %d', npxResult.status);
126
175
 
127
176
  if (npxResult.status === 0 && npxResult.stdout) {
177
+ debugStrategy('npx tsx succeeded, parsing output');
128
178
  try {
129
179
  const output = JSON.parse(npxResult.stdout) as { success: boolean; filterCode?: string };
130
180
  if (output.success === true && typeof output.filterCode === 'string' && output.filterCode.length > 0) {
181
+ debugStrategy('Successfully parsed filter code, creating function');
131
182
  // Create a function from the filter code
132
183
  // eslint-disable-next-line @typescript-eslint/no-implied-eval, @typescript-eslint/no-unsafe-call
133
184
  const filter = new Function('return ' + output.filterCode)() as FilterFunctionType;
185
+ debugStrategy('Filter function created successfully');
134
186
  return filter;
135
187
  }
136
- } catch {
188
+ debugStrategy('Output missing success flag or filter code');
189
+ } catch (parseError) {
190
+ debugStrategy('Failed to parse npx output: %O', parseError);
137
191
  // JSON parse failed, try another approach
138
192
  }
193
+ } else {
194
+ debugStrategy('npx tsx failed or no output');
195
+ if (npxResult.stderr) {
196
+ debugStrategy('Error output: %s', npxResult.stderr);
197
+ }
139
198
  }
140
199
 
141
200
  return null;
142
201
  }
143
202
 
144
203
  private async tryNodeLoaderOptions(tempDir: string, filterUrl: string): Promise<FilterFunctionType | null> {
204
+ debugStrategy('Strategy: Node loader options');
145
205
  // Third attempt: Create a wrapper that uses dynamic import with tsx
146
206
  const wrapperFile = this.prepareTemplate(tempDir, 'tsx-wrapper.mjs', filterUrl);
207
+ debugStrategy('Prepared wrapper file: %s', wrapperFile);
147
208
 
148
209
  // Try with various Node.js loader configurations
149
210
  const loaderOptions = [
@@ -152,53 +213,73 @@ export class FilterLoader {
152
213
  ['--require', 'tsx'],
153
214
  ['--import', 'tsx'],
154
215
  ];
216
+ debugStrategy('Will try %d loader configurations', loaderOptions.length);
155
217
 
156
218
  for (const options of loaderOptions) {
219
+ debugStrategy('Trying loader options: %s', options.join(' '));
157
220
  const testResult = spawnSync('node', [...options, wrapperFile], {
158
221
  cwd: process.cwd(),
159
222
  encoding: 'utf-8',
160
223
  env: { ...process.env },
161
224
  });
225
+ debugStrategy('Exit code: %d', testResult.status);
162
226
 
163
227
  if (testResult.status === 0) {
228
+ debugStrategy('Configuration works! Loading final filter');
164
229
  // This configuration works! Use it to load the actual filter
165
230
  const finalFile = this.prepareTemplate(tempDir, 'tsx-final-loader.mjs', filterUrl);
166
231
  const finalModule = (await import(pathToFileURL(finalFile).href)) as { filter: FilterFunctionType };
232
+ debugStrategy('Filter loaded successfully with options: %s', options.join(' '));
167
233
  return finalModule.filter;
234
+ } else if (testResult.stderr) {
235
+ debugStrategy('Error with %s: %s', options.join(' '), testResult.stderr);
168
236
  }
169
237
  }
170
238
 
239
+ debugStrategy('All loader options failed');
171
240
  return null;
172
241
  }
173
242
 
174
243
  private prepareTemplate(tempDir: string, templateName: string, filterPath: string): string {
244
+ debugTemplate('Preparing template: %s', templateName);
245
+ debugTemplate('Filter path: %s', filterPath);
175
246
  const templatePath = join(this.templatesDir, templateName);
176
247
  const outputPath = join(tempDir, templateName);
248
+ debugTemplate('Template path: %s', templatePath);
249
+ debugTemplate('Output path: %s', outputPath);
177
250
 
178
251
  // Read the template
179
252
  let content: string;
180
253
  if (existsSync(templatePath)) {
254
+ debugTemplate('Reading template from source');
181
255
  content = readFileSync(templatePath, 'utf-8');
182
256
  } else {
257
+ debugTemplate('Template not in source, checking dist');
183
258
  // Fallback to dist directory if running from compiled code
184
259
  const distTemplatePath = templatePath.replace('/src/', '/dist/');
260
+ debugTemplate('Checking dist path: %s', distTemplatePath);
185
261
  if (existsSync(distTemplatePath)) {
262
+ debugTemplate('Reading template from dist');
186
263
  content = readFileSync(distTemplatePath, 'utf-8');
187
264
  } else {
265
+ debugTemplate('ERROR: Template not found in source or dist');
188
266
  throw new Error(`Template not found: ${templateName}`);
189
267
  }
190
268
  }
191
269
 
192
270
  // Replace the placeholder with the actual filter path
193
271
  content = content.replace(/__FILTER_PATH__/g, filterPath);
272
+ debugTemplate('Replaced filter path placeholder');
194
273
 
195
274
  // Write the prepared script
196
275
  writeFileSync(outputPath, content);
276
+ debugTemplate('Written prepared script to: %s', outputPath);
197
277
 
198
278
  return outputPath;
199
279
  }
200
280
 
201
281
  cleanup(): void {
282
+ debug('FilterLoader cleanup called');
202
283
  // No cleanup needed
203
284
  }
204
285
  }