Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance Config Loading and Merging Logic with Parallel Checks #139

Closed
wants to merge 1 commit into from
Closed
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
118 changes: 56 additions & 62 deletions src/config/configLoad.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,106 +10,100 @@
const defaultConfigPath = 'repopack.config.json';

const getGlobalConfigPath = () => {
return path.join(getGlobalDirectory(), 'repopack.config.json');

Check failure on line 13 in src/config/configLoad.ts

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 16.x)

tests/config/configLoad.test.ts > configLoad > loadFileConfig > should load and parse a valid local config file

TypeError: The "path" argument must be of type string. Received undefined ❯ getGlobalConfigPath src/config/configLoad.ts:13:15 ❯ Module.loadFileConfig src/config/configLoad.ts:24:21 ❯ tests/config/configLoad.test.ts:37:28 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { code: 'ERR_INVALID_ARG_TYPE' }
};

export const loadFileConfig = async (rootDir: string, argConfigPath: string | null): Promise<RepopackConfigFile> => {
let useDefaultConfig = false;
let configPath = argConfigPath;
if (!configPath) {
useDefaultConfig = true;
configPath = defaultConfigPath;
}
let configPath = argConfigPath ?? defaultConfigPath;

const fullPath = path.resolve(rootDir, configPath);

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

// Check local file existence
const isLocalFileExists = await fs
.stat(fullPath)
.then((stats) => stats.isFile())
.catch(() => false);
const [isLocalFileExists, isGlobalFileExists] = await Promise.all([
checkFileExists(fullPath),
checkFileExists(getGlobalConfigPath()),
]);

if (isLocalFileExists) {
return await loadAndValidateConfig(fullPath);
}

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

const isGlobalFileExists = await fs
.stat(globalConfigPath)
.then((stats) => stats.isFile())
.catch(() => false);
if (isGlobalFileExists) {
return await loadAndValidateConfig(getGlobalConfigPath());
}

if (isGlobalFileExists) {
return await loadAndValidateConfig(globalConfigPath);
}
logger.note(
`No custom config found at ${configPath} or global config. You can add a config file for additional settings. Please check https://github.com/yamadashy/repopack for more information.`,
);
return {};
};

logger.note(
`No custom config found at ${configPath} or global config at ${globalConfigPath}.\nYou can add a config file for additional settings. Please check https://github.com/yamadashy/repopack for more information.`,
);
return {};
}
throw new RepopackError(`Config file not found at ${configPath}`);
const checkFileExists = async (filePath: string): Promise<boolean> => {
return fs
.stat(filePath)
.then((stats) => stats.isFile())
.catch(() => false);
};

const loadAndValidateConfig = async (filePath: string): Promise<RepopackConfigFile> => {

Check failure on line 48 in src/config/configLoad.ts

View workflow job for this annotation

GitHub Actions / Build and run (ubuntu-latest, 16.x)

Function lacks ending return statement and return type does not include 'undefined'.

Check failure on line 48 in src/config/configLoad.ts

View workflow job for this annotation

GitHub Actions / Build and run (ubuntu-latest, 20.x)

Function lacks ending return statement and return type does not include 'undefined'.

Check failure on line 48 in src/config/configLoad.ts

View workflow job for this annotation

GitHub Actions / Build and run (ubuntu-latest, 18.x)

Function lacks ending return statement and return type does not include 'undefined'.

Check failure on line 48 in src/config/configLoad.ts

View workflow job for this annotation

GitHub Actions / Build and run (macos-latest, 20.x)

Function lacks ending return statement and return type does not include 'undefined'.

Check failure on line 48 in src/config/configLoad.ts

View workflow job for this annotation

GitHub Actions / Lint TypeScript

Function lacks ending return statement and return type does not include 'undefined'.
try {
const fileContent = await fs.readFile(filePath, 'utf-8');
const config = JSON.parse(fileContent);
validateConfig(config);
return config;
} catch (error) {
if (error instanceof RepopackConfigValidationError) {
throw new RepopackError(`Invalid configuration in ${filePath}: ${error.message}`);
}
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}`);
handleError(error, filePath);
}
};

export const mergeConfigs = (
const handleError = (error: unknown, filePath: string): void => {
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
throw new RepopackError(`Error loading config from ${filePath}: ${errorMessage}`);
};

const mergeConfigs = (
cwd: string,
fileConfig: RepopackConfigFile,
cliConfig: RepopackConfigCli,
): RepopackConfigMerged => {
// If the output file path is not provided in the config file or CLI, use the default file path for the style
if (cliConfig.output?.filePath == null && fileConfig.output?.filePath == null) {
const style = cliConfig.output?.style || fileConfig.output?.style || defaultConfig.output.style;
defaultConfig.output.filePath = defaultFilePathMap[style];
}
const output = mergeOutput(fileConfig.output, cliConfig.output);
const ignore = mergeIgnore(fileConfig.ignore, cliConfig.ignore);
const include = Array.prototype.flat([defaultConfig.include || [], fileConfig.include || [], cliConfig.include || []]);

Check failure on line 71 in src/config/configLoad.ts

View workflow job for this annotation

GitHub Actions / Build and run (ubuntu-latest, 16.x)

Argument of type 'string[][]' is not assignable to parameter of type 'number'.

Check failure on line 71 in src/config/configLoad.ts

View workflow job for this annotation

GitHub Actions / Build and run (ubuntu-latest, 20.x)

Argument of type 'string[][]' is not assignable to parameter of type 'number'.

Check failure on line 71 in src/config/configLoad.ts

View workflow job for this annotation

GitHub Actions / Build and run (ubuntu-latest, 18.x)

Argument of type 'string[][]' is not assignable to parameter of type 'number'.

Check failure on line 71 in src/config/configLoad.ts

View workflow job for this annotation

GitHub Actions / Build and run (macos-latest, 20.x)

Argument of type 'string[][]' is not assignable to parameter of type 'number'.

Check failure on line 71 in src/config/configLoad.ts

View workflow job for this annotation

GitHub Actions / Lint TypeScript

Argument of type 'string[][]' is not assignable to parameter of type 'number'.

return {
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 || [])],
output,
ignore,
include,
security: {
...defaultConfig.security,
...fileConfig.security,
...cliConfig.security,
},
};
};

const mergeOutput = (fileOutput: any, cliOutput: any) => {
const style = cliOutput?.style || fileOutput?.style || defaultConfig.output.style;
const filePath = cliOutput?.filePath ?? fileOutput?.filePath ?? defaultFilePathMap[style];

Check failure on line 88 in src/config/configLoad.ts

View workflow job for this annotation

GitHub Actions / Build and run (ubuntu-latest, 16.x)

Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'Record<RepopackOutputStyle, string>'.

Check failure on line 88 in src/config/configLoad.ts

View workflow job for this annotation

GitHub Actions / Build and run (ubuntu-latest, 20.x)

Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'Record<RepopackOutputStyle, string>'.

Check failure on line 88 in src/config/configLoad.ts

View workflow job for this annotation

GitHub Actions / Build and run (ubuntu-latest, 18.x)

Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'Record<RepopackOutputStyle, string>'.

Check failure on line 88 in src/config/configLoad.ts

View workflow job for this annotation

GitHub Actions / Build and run (macos-latest, 20.x)

Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'Record<RepopackOutputStyle, string>'.

Check failure on line 88 in src/config/configLoad.ts

View workflow job for this annotation

GitHub Actions / Lint TypeScript

Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'Record<RepopackOutputStyle, string>'.

return {
...defaultConfig.output,
...fileOutput,
...cliOutput,
filePath,
};
};

const mergeIgnore = (fileIgnore: any, cliIgnore: any) => {
return {
...defaultConfig.ignore,
...fileIgnore,
...cliIgnore,
customPatterns: [
...(defaultConfig.ignore.customPatterns || []),
...(fileIgnore?.customPatterns || []),
...(cliIgnore?.customPatterns || []),
],
};
};
Loading