Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"scripts": {
"clean": "rimraf lib",
"build": "npm run clean && tsc -p tsconfig.build.json --sourceMap --declaration",
"lint": "biome lint --write && biome format --write && biome check --write && tsc --noEmit && secretlint **/*",
"lint": "biome check --write && tsc --noEmit && secretlint **/*",
"test": "vitest",
"test-coverage": "vitest run --coverage",
"cli-run": "npm run build && node --trace-warnings bin/repopack",
Expand Down Expand Up @@ -63,7 +63,8 @@
"p-map": "^7.0.2",
"picocolors": "^1.1.0",
"strip-comments": "^2.0.1",
"tiktoken": "^1.0.16"
"tiktoken": "^1.0.16",
"zod": "^3.23.8"
},
"devDependencies": {
"@biomejs/biome": "^1.9.1",
Expand Down
66 changes: 40 additions & 26 deletions src/cli/actions/defaultActionRunner.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import path from 'node:path';
import { loadFileConfig, mergeConfigs } from '../../config/configLoader.js';
import type {
RepopackConfigCli,
RepopackConfigFile,
RepopackConfigMerged,
RepopackOutputStyle,
} from '../../config/configTypes.js';
import {
type RepopackConfigCli,
type RepopackConfigFile,
type RepopackConfigMerged,
type RepopackOutputStyle,
repopackConfigCliSchema,
} from '../../config/configSchema.js';
import { type PackResult, pack } from '../../core/packager.js';
import { rethrowValidationErrorIfZodError } from '../../shared/errorHandler.js';
import { logger } from '../../shared/logger.js';
import { printCompletion, printSecurityCheck, printSummary, printTopFiles } from '../cliPrinter.js';
import type { CliOptions } from '../cliRunner.js';
Expand All @@ -28,26 +30,8 @@ export const runDefaultAction = async (
const fileConfig: RepopackConfigFile = await loadFileConfig(cwd, options.config ?? null);
logger.trace('Loaded file config:', fileConfig);

// Parse the CLI options
const cliConfig: RepopackConfigCli = {};
if (options.output) {
cliConfig.output = { filePath: options.output };
}
if (options.include) {
cliConfig.include = options.include.split(',');
}
if (options.ignore) {
cliConfig.ignore = { customPatterns: options.ignore.split(',') };
}
if (options.topFilesLen !== undefined) {
cliConfig.output = { ...cliConfig.output, topFilesLength: options.topFilesLen };
}
if (options.outputShowLineNumbers !== undefined) {
cliConfig.output = { ...cliConfig.output, showLineNumbers: options.outputShowLineNumbers };
}
if (options.style) {
cliConfig.output = { ...cliConfig.output, style: options.style.toLowerCase() as RepopackOutputStyle };
}
// Parse the CLI options into a config
const cliConfig: RepopackConfigCli = buildCliConfig(options);
logger.trace('CLI config:', cliConfig);

// Merge default, file, and CLI configs
Expand Down Expand Up @@ -99,3 +83,33 @@ export const runDefaultAction = async (
config,
};
};

const buildCliConfig = (options: CliOptions): RepopackConfigCli => {
const cliConfig: RepopackConfigCli = {};

if (options.output) {
cliConfig.output = { filePath: options.output };
}
if (options.include) {
cliConfig.include = options.include.split(',');
}
if (options.ignore) {
cliConfig.ignore = { customPatterns: options.ignore.split(',') };
}
if (options.topFilesLen !== undefined) {
cliConfig.output = { ...cliConfig.output, topFilesLength: options.topFilesLen };
}
if (options.outputShowLineNumbers !== undefined) {
cliConfig.output = { ...cliConfig.output, showLineNumbers: options.outputShowLineNumbers };
}
if (options.style) {
cliConfig.output = { ...cliConfig.output, style: options.style.toLowerCase() as RepopackOutputStyle };
}

try {
return repopackConfigCliSchema.parse(cliConfig);
} catch (error) {
rethrowValidationErrorIfZodError(error, 'Invalid cli arguments');
throw error;
}
Comment on lines +110 to +114
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enhance Error Handling in Configuration Parsing

While the current error handling rethrows validation errors, consider providing more detailed feedback to the user. This can include which specific CLI option caused the validation to fail, making it easier for users to correct their input.

You might adjust the catch block as follows to include detailed error messages:

} catch (error) {
  rethrowValidationErrorIfZodError(error, 'Invalid CLI arguments');
+  if (error instanceof ZodError) {
+    logger.error('Configuration validation failed:', error.errors);
+  }
  throw error;
}

This change logs detailed validation errors without affecting the existing error flow.

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return repopackConfigCliSchema.parse(cliConfig);
} catch (error) {
rethrowValidationErrorIfZodError(error, 'Invalid cli arguments');
throw error;
}
return repopackConfigCliSchema.parse(cliConfig);
} catch (error) {
rethrowValidationErrorIfZodError(error, 'Invalid cli arguments');
if (error instanceof ZodError) {
logger.error('Configuration validation failed:', error.errors);
}
throw error;
}

};
Comment on lines +87 to +115
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential TypeError When Spreading Undefined cliConfig.output

In the buildCliConfig function, there's a risk of a TypeError when spreading cliConfig.output if it hasn't been initialized. If options.output is not provided, cliConfig.output remains undefined, and spreading it using { ...cliConfig.output, ... } will cause an error.

To fix this issue, ensure that cliConfig.output is initialized before attempting to spread it. Here's how you can modify the code:

const buildCliConfig = (options: CliOptions): RepopackConfigCli => {
  const cliConfig: RepopackConfigCli = {};
+  // Initialize cliConfig.output to an empty object
+  cliConfig.output = {};

  if (options.output) {
    cliConfig.output = { filePath: options.output };
  }

  if (options.include) {
    cliConfig.include = options.include.split(',');
  }

  if (options.ignore) {
    cliConfig.ignore = { customPatterns: options.ignore.split(',') };
  }

  if (options.topFilesLen !== undefined) {
-    cliConfig.output = { ...cliConfig.output, topFilesLength: options.topFilesLen };
+    cliConfig.output = {
+      ...cliConfig.output,
+      topFilesLength: options.topFilesLen,
+    };
  }

  if (options.outputShowLineNumbers !== undefined) {
    cliConfig.output = {
      ...cliConfig.output,
      showLineNumbers: options.outputShowLineNumbers,
    };
  }

  if (options.style) {
    cliConfig.output = {
      ...cliConfig.output,
      style: options.style.toLowerCase() as RepopackOutputStyle,
    };
  }

  try {
    return repopackConfigCliSchema.parse(cliConfig);
  } catch (error) {
    rethrowValidationErrorIfZodError(error, 'Invalid CLI arguments');
    throw error;
  }
};

Alternatively, you can check if cliConfig.output is undefined before spreading:

if (options.topFilesLen !== undefined) {
-    cliConfig.output = { ...cliConfig.output, topFilesLength: options.topFilesLen };
+    cliConfig.output = {
+      ...(cliConfig.output || {}),
+      topFilesLength: options.topFilesLen,
+    };
  }
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const buildCliConfig = (options: CliOptions): RepopackConfigCli => {
const cliConfig: RepopackConfigCli = {};
if (options.output) {
cliConfig.output = { filePath: options.output };
}
if (options.include) {
cliConfig.include = options.include.split(',');
}
if (options.ignore) {
cliConfig.ignore = { customPatterns: options.ignore.split(',') };
}
if (options.topFilesLen !== undefined) {
cliConfig.output = { ...cliConfig.output, topFilesLength: options.topFilesLen };
}
if (options.outputShowLineNumbers !== undefined) {
cliConfig.output = { ...cliConfig.output, showLineNumbers: options.outputShowLineNumbers };
}
if (options.style) {
cliConfig.output = { ...cliConfig.output, style: options.style.toLowerCase() as RepopackOutputStyle };
}
try {
return repopackConfigCliSchema.parse(cliConfig);
} catch (error) {
rethrowValidationErrorIfZodError(error, 'Invalid cli arguments');
throw error;
}
};
const buildCliConfig = (options: CliOptions): RepopackConfigCli => {
const cliConfig: RepopackConfigCli = {};
// Initialize cliConfig.output to an empty object
cliConfig.output = {};
if (options.output) {
cliConfig.output = { filePath: options.output };
}
if (options.include) {
cliConfig.include = options.include.split(',');
}
if (options.ignore) {
cliConfig.ignore = { customPatterns: options.ignore.split(',') };
}
if (options.topFilesLen !== undefined) {
cliConfig.output = {
...cliConfig.output,
topFilesLength: options.topFilesLen,
};
}
if (options.outputShowLineNumbers !== undefined) {
cliConfig.output = {
...cliConfig.output,
showLineNumbers: options.outputShowLineNumbers,
};
}
if (options.style) {
cliConfig.output = {
...cliConfig.output,
style: options.style.toLowerCase() as RepopackOutputStyle,
};
}
try {
return repopackConfigCliSchema.parse(cliConfig);
} catch (error) {
rethrowValidationErrorIfZodError(error, 'Invalid CLI arguments');
throw error;
}
};

2 changes: 1 addition & 1 deletion src/cli/actions/initActionRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import fs from 'node:fs/promises';
import path from 'node:path';
import * as prompts from '@clack/prompts';
import pc from 'picocolors';
import type { RepopackConfigFile, RepopackOutputStyle } from '../../config/configTypes.js';
import type { RepopackConfigFile, RepopackOutputStyle } from '../../config/configSchema.js';
import { defaultConfig } from '../../config/defaultConfig.js';
import { getGlobalDirectory } from '../../config/globalDirectory.js';
import { logger } from '../../shared/logger.js';
Expand Down
2 changes: 1 addition & 1 deletion src/cli/cliPrinter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import path from 'node:path';
import pc from 'picocolors';
import type { RepopackConfigMerged } from '../config/configTypes.js';
import type { RepopackConfigMerged } from '../config/configSchema.js';
import type { SuspiciousFileResult } from '../core/security/securityCheckRunner.js';
import { logger } from '../shared/logger.js';

Expand Down
2 changes: 1 addition & 1 deletion src/cli/cliRunner.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import process from 'node:process';
import { type OptionValues, program } from 'commander';
import pc from 'picocolors';
import type { RepopackOutputStyle } from '../config/configTypes.js';
import type { RepopackOutputStyle } from '../config/configSchema.js';
import { getVersion } from '../core/file/packageJsonParser.js';
import { handleError } from '../shared/errorHandler.js';
import { logger } from '../shared/logger.js';
Expand Down
78 changes: 44 additions & 34 deletions src/config/configLoader.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import * as fs from 'node:fs/promises';
import path from 'node:path';
import { RepopackError } from '../shared/errorHandler.js';
import { z } from 'zod';
import { RepopackError, rethrowValidationErrorIfZodError } from '../shared/errorHandler.js';
Comment on lines +3 to +4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import: 'z' from 'zod'

The imported z from 'zod' is not directly used in this file. Since the schema parsing is handled through imported schemas (repopackConfigFileSchema and repopackConfigMergedSchema), the direct import of z may not be necessary.

Consider removing the unused import to keep the code clean:

-import { z } from 'zod';
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { z } from 'zod';
import { RepopackError, rethrowValidationErrorIfZodError } from '../shared/errorHandler.js';
import { RepopackError, rethrowValidationErrorIfZodError } from '../shared/errorHandler.js';

import { logger } from '../shared/logger.js';
import type { RepopackConfigCli, RepopackConfigFile, RepopackConfigMerged } from './configTypes.js';
import { RepopackConfigValidationError, validateConfig } from './configValidator.js';
import {
type RepopackConfigCli,
type RepopackConfigFile,
type RepopackConfigMerged,
repopackConfigFileSchema,
repopackConfigMergedSchema,
} from './configSchema.js';
import { defaultConfig } from './defaultConfig.js';
import { getGlobalDirectory } from './globalDirectory.js';

Expand All @@ -25,7 +31,6 @@ export const loadFileConfig = async (rootDir: string, argConfigPath: string | nu

logger.trace('Loading local config from:', fullPath);

// Check local file existence
const isLocalFileExists = await fs
.stat(fullPath)
.then((stats) => stats.isFile())
Expand All @@ -36,7 +41,6 @@ export const loadFileConfig = async (rootDir: string, argConfigPath: string | nu
}

if (useDefaultConfig) {
// Try to load global config
const globalConfigPath = getGlobalConfigPath();
logger.trace('Loading global config from:', globalConfigPath);

Expand All @@ -61,12 +65,9 @@ const loadAndValidateConfig = async (filePath: string): Promise<RepopackConfigFi
try {
const fileContent = await fs.readFile(filePath, 'utf-8');
const config = JSON.parse(fileContent);
validateConfig(config);
return config;
return repopackConfigFileSchema.parse(config);
} catch (error) {
if (error instanceof RepopackConfigValidationError) {
throw new RepopackError(`Invalid configuration in ${filePath}: ${error.message}`);
}
rethrowValidationErrorIfZodError(error, 'Invalid config schema');
Comment on lines +68 to +70
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure consistent error handling in configuration parsing

When parsing the configuration file with repopackConfigFileSchema.parse(config), any validation errors thrown by Zod are handled by rethrowValidationErrorIfZodError(error, 'Invalid config schema');. If this function rethrows the error, the subsequent error handling code might be unreachable. To avoid redundancy and potential confusion, consider simplifying the error handling to ensure that errors are handled appropriately without overlapping.

Apply this diff to streamline the error handling:

} catch (error) {
  rethrowValidationErrorIfZodError(error, 'Invalid config schema');
- if (error instanceof SyntaxError) {
-   throw new RepopackError(`Invalid JSON in config file ${filePath}: ${error.message}`);
- }
- if (error instanceof Error) {
-   throw new RepopackError(`Error loading config from ${filePath}: ${error.message}`);
- }
- throw new RepopackError(`Error loading config from ${filePath}`);
}

Ensure that rethrowValidationErrorIfZodError handles all necessary error cases, including JSON parsing errors.

Committable suggestion was skipped due to low confidence.

if (error instanceof SyntaxError) {
throw new RepopackError(`Invalid JSON in config file ${filePath}: ${error.message}`);
}
Expand All @@ -81,27 +82,36 @@ export const mergeConfigs = (
cwd: string,
fileConfig: RepopackConfigFile,
cliConfig: RepopackConfigCli,
): RepopackConfigMerged => ({
cwd,
output: {
...defaultConfig.output,
...fileConfig.output,
...cliConfig.output,
},
ignore: {
...defaultConfig.ignore,
...fileConfig.ignore,
...cliConfig.ignore,
customPatterns: [
...(defaultConfig.ignore.customPatterns || []),
...(fileConfig.ignore?.customPatterns || []),
...(cliConfig.ignore?.customPatterns || []),
],
},
include: [...(defaultConfig.include || []), ...(fileConfig.include || []), ...(cliConfig.include || [])],
security: {
...defaultConfig.security,
...fileConfig.security,
...cliConfig.security,
},
});
): RepopackConfigMerged => {
const mergedConfig = {
cwd,
output: {
...defaultConfig.output,
...fileConfig.output,
...cliConfig.output,
},
ignore: {
...defaultConfig.ignore,
...fileConfig.ignore,
...cliConfig.ignore,
customPatterns: [
...(defaultConfig.ignore.customPatterns || []),
...(fileConfig.ignore?.customPatterns || []),
...(cliConfig.ignore?.customPatterns || []),
],
},
include: [...(defaultConfig.include || []), ...(fileConfig.include || []), ...(cliConfig.include || [])],
security: {
...defaultConfig.security,
...fileConfig.security,
...cliConfig.security,
},
};

Comment on lines +85 to +110
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider deep merging for nested configuration objects

When merging configurations, properties like output, ignore, and security are being shallowly merged. If these properties contain nested objects or arrays, a shallow merge might not combine them as expected, potentially overwriting entire sections of the configuration.

To ensure all nested properties are correctly merged, consider using a deep merge utility like lodash.merge. Here's how you might implement it:

+ import merge from 'lodash.merge';

...

export const mergeConfigs = (
  cwd: string,
  fileConfig: RepopackConfigFile,
  cliConfig: RepopackConfigCli,
): RepopackConfigMerged => {
- const mergedConfig = {
-   cwd,
-   output: {
-     ...defaultConfig.output,
-     ...fileConfig.output,
-     ...cliConfig.output,
-   },
-   ignore: {
-     ...defaultConfig.ignore,
-     ...fileConfig.ignore,
-     ...cliConfig.ignore,
-     customPatterns: [
-       ...(defaultConfig.ignore.customPatterns || []),
-       ...(fileConfig.ignore?.customPatterns || []),
-       ...(cliConfig.ignore?.customPatterns || []),
-     ],
-   },
-   include: [...(defaultConfig.include || []), ...(fileConfig.include || []), ...(cliConfig.include || [])],
-   security: {
-     ...defaultConfig.security,
-     ...fileConfig.security,
-     ...cliConfig.security,
-   },
- };
+ const mergedConfig = merge({}, defaultConfig, fileConfig, cliConfig, { cwd });

  try {
    return repopackConfigMergedSchema.parse(mergedConfig);
  } catch (error) {
    rethrowValidationErrorIfZodError(error, 'Invalid merged config');
    throw error;
  }
};

This approach provides a more robust merging strategy, ensuring that all configuration values are appropriately combined without unintended overwrites.

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
): RepopackConfigMerged => {
const mergedConfig = {
cwd,
output: {
...defaultConfig.output,
...fileConfig.output,
...cliConfig.output,
},
ignore: {
...defaultConfig.ignore,
...fileConfig.ignore,
...cliConfig.ignore,
customPatterns: [
...(defaultConfig.ignore.customPatterns || []),
...(fileConfig.ignore?.customPatterns || []),
...(cliConfig.ignore?.customPatterns || []),
],
},
include: [...(defaultConfig.include || []), ...(fileConfig.include || []), ...(cliConfig.include || [])],
security: {
...defaultConfig.security,
...fileConfig.security,
...cliConfig.security,
},
};
): RepopackConfigMerged => {
const mergedConfig = merge({}, defaultConfig, fileConfig, cliConfig, { cwd });
try {
return repopackConfigMergedSchema.parse(mergedConfig);
} catch (error) {
rethrowValidationErrorIfZodError(error, 'Invalid merged config');
throw error;
}
};

try {
return repopackConfigMergedSchema.parse(mergedConfig);
} catch (error) {
rethrowValidationErrorIfZodError(error, 'Invalid merged config');
throw error;
Comment on lines +112 to +115
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove redundant error rethrow in merged configuration validation

After calling rethrowValidationErrorIfZodError(error, 'Invalid merged config');, the subsequent throw error; may be unnecessary if the function already throws the error. This redundancy could lead to confusion about which error is ultimately thrown.

Apply this diff to eliminate the redundant throw statement:

} catch (error) {
  rethrowValidationErrorIfZodError(error, 'Invalid merged config');
- throw error;
}

This change ensures that the error handling is clear and that only the intended error is propagated.

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return repopackConfigMergedSchema.parse(mergedConfig);
} catch (error) {
rethrowValidationErrorIfZodError(error, 'Invalid merged config');
throw error;
return repopackConfigMergedSchema.parse(mergedConfig);
} catch (error) {
rethrowValidationErrorIfZodError(error, 'Invalid merged config');
}

}
};
79 changes: 79 additions & 0 deletions src/config/configSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { z } from 'zod';
import { RepopackError } from '../shared/errorHandler.js';

export const repopackOutputStyleSchema = z.enum(['plain', 'xml']);

export type RepopackOutputStyle = z.infer<typeof repopackOutputStyleSchema>;

const repopackConfigBaseSchema = z.object({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Export repopackConfigBaseSchema for Consistency and Reusability

Since repopackConfigBaseSchema serves as the foundation for other schemas and might be useful in other modules or for further extensions, consider exporting it to promote reusability and maintain consistency.

Apply this diff to export the base schema:

-const repopackConfigBaseSchema = z.object({
+export const repopackConfigBaseSchema = z.object({
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const repopackConfigBaseSchema = z.object({
export const repopackConfigBaseSchema = z.object({

output: z
.object({
filePath: z.string().optional(),
style: repopackOutputStyleSchema.optional(),
headerText: z.string().optional(),
instructionFilePath: z.string().optional(),
removeComments: z.boolean().optional(),
removeEmptyLines: z.boolean().optional(),
topFilesLength: z.number().optional(),
showLineNumbers: z.boolean().optional(),
})
.optional(),
include: z.array(z.string()).optional(),
ignore: z
.object({
useGitignore: z.boolean().optional(),
useDefaultPatterns: z.boolean().optional(),
customPatterns: z.array(z.string()).optional(),
})
.optional(),
security: z
.object({
enableSecurityCheck: z.boolean().optional(),
})
.optional(),
});

export const repopackConfigDefaultSchema = repopackConfigBaseSchema.and(
z.object({
output: z.object({
Comment on lines +36 to +38
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use .extend() Instead of .and() for Object Schema Extension

When extending an object schema, it's more appropriate to use .extend() rather than .and(). The .extend() method is specifically designed for adding new fields to an existing schema and ensures better handling of overlapping keys.

Apply this diff to replace .and() with .extend():

-export const repopackConfigDefaultSchema = repopackConfigBaseSchema.and(
+export const repopackConfigDefaultSchema = repopackConfigBaseSchema.extend(
  z.object({
    output: z.object({
      filePath: z.string(),
      style: repopackOutputStyleSchema,
      headerText: z.string().optional(),
      instructionFilePath: z.string().optional(),
      removeComments: z.boolean(),
      removeEmptyLines: z.boolean(),
      topFilesLength: z.number(),
      showLineNumbers: z.boolean(),
    }),
    include: z.array(z.string()),
    ignore: z.object({
      useGitignore: z.boolean(),
      useDefaultPatterns: z.boolean(),
      customPatterns: z.array(z.string()).optional(),
    }),
    security: z.object({
      enableSecurityCheck: z.boolean(),
    }),
  }),
);
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const repopackConfigDefaultSchema = repopackConfigBaseSchema.and(
z.object({
output: z.object({
export const repopackConfigDefaultSchema = repopackConfigBaseSchema.extend(
z.object({
output: z.object({

filePath: z.string(),
style: repopackOutputStyleSchema,
headerText: z.string().optional(),
instructionFilePath: z.string().optional(),
removeComments: z.boolean(),
removeEmptyLines: z.boolean(),
topFilesLength: z.number(),
showLineNumbers: z.boolean(),
}),
include: z.array(z.string()),
ignore: z.object({
useGitignore: z.boolean(),
useDefaultPatterns: z.boolean(),
customPatterns: z.array(z.string()).optional(),
}),
security: z.object({
enableSecurityCheck: z.boolean(),
}),
}),
);

export type RepopackConfigDefault = z.infer<typeof repopackConfigDefaultSchema>;

export const repopackConfigFileSchema = repopackConfigBaseSchema;

export type RepopackConfigFile = z.infer<typeof repopackConfigFileSchema>;

export const repopackConfigCliSchema = repopackConfigBaseSchema;

export type RepopackConfigCli = z.infer<typeof repopackConfigCliSchema>;

export const repopackConfigMergedSchema = repopackConfigDefaultSchema
.and(repopackConfigFileSchema)
.and(repopackConfigCliSchema)
.and(
z.object({
cwd: z.string(),
}),
);
Comment on lines +70 to +77
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Address Overlapping Keys in Combined Schemas

When combining multiple schemas that may have overlapping keys, using .and() can lead to conflicts or unintended behavior. To properly merge schemas with overlapping properties, consider using .merge() or restructuring the schemas to avoid duplication.

Apply this diff to use .merge() and ensure correct schema merging:

-export const repopackConfigMergedSchema = repopackConfigDefaultSchema
-  .and(repopackConfigFileSchema)
-  .and(repopackConfigCliSchema)
-  .and(
+export const repopackConfigMergedSchema = repopackConfigDefaultSchema
+  .merge(repopackConfigFileSchema)
+  .merge(repopackConfigCliSchema)
+  .extend(
    z.object({
      cwd: z.string(),
    }),
  );
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const repopackConfigMergedSchema = repopackConfigDefaultSchema
.and(repopackConfigFileSchema)
.and(repopackConfigCliSchema)
.and(
z.object({
cwd: z.string(),
}),
);
export const repopackConfigMergedSchema = repopackConfigDefaultSchema
.merge(repopackConfigFileSchema)
.merge(repopackConfigCliSchema)
.extend(
z.object({
cwd: z.string(),
}),
);


export type RepopackConfigMerged = z.infer<typeof repopackConfigMergedSchema>;
Loading