python2ib
Version:
Convert Python code to IB Pseudocode format
169 lines • 5.57 kB
JavaScript
import { readFileSync, existsSync, writeFileSync } from 'fs';
import { join } from 'path';
import { ConfigurationError } from '../errors/index.js';
import { DEFAULT_CONFIG as BASE_DEFAULT_CONFIG } from '../types/config.js';
/**
* Default configuration
*/
export const DEFAULT_CONFIG = {
...BASE_DEFAULT_CONFIG
};
/**
* Configuration file names to search for
*/
const CONFIG_FILENAMES = [
'.python2ibrc',
'.python2ibrc.json',
'python2ib.config.json',
'python2ib.config.js'
];
/**
* Load configuration from file
*/
export function loadConfigFromFile(configPath) {
let configFilePath = null;
if (configPath) {
// Use specified config file
if (!existsSync(configPath)) {
throw new ConfigurationError(`Configuration file not found: ${configPath}`, configPath);
}
configFilePath = configPath;
}
else {
// Search for config file in current directory
for (const filename of CONFIG_FILENAMES) {
const fullPath = join(process.cwd(), filename);
if (existsSync(fullPath)) {
configFilePath = fullPath;
break;
}
}
}
if (!configFilePath) {
return {}; // No config file found, use defaults
}
try {
const configContent = readFileSync(configFilePath, 'utf8');
if (configFilePath.endsWith('.js')) {
// Handle JavaScript config files (basic support)
throw new ConfigurationError('JavaScript config files are not yet supported. Please use JSON format.', configFilePath);
}
const config = JSON.parse(configContent);
validateConfig(config, configFilePath);
return config;
}
catch (error) {
if (error instanceof SyntaxError) {
throw new ConfigurationError(`Invalid JSON in configuration file: ${error.message}`, configFilePath);
}
throw error;
}
}
/**
* Validate configuration object
*/
function validateConfig(config, configPath) {
if (typeof config !== 'object' || config === null) {
throw new ConfigurationError('Configuration must be a JSON object', configPath);
}
// Validate indentSize
if ('indentSize' in config) {
if (typeof config.indentSize !== 'number' || config.indentSize < 0) {
throw new ConfigurationError('indentSize must be a non-negative number', configPath);
}
}
// Validate outputFormat
if ('outputFormat' in config) {
if (!['plain', 'markdown'].includes(config.outputFormat)) {
throw new ConfigurationError('outputFormat must be "plain" or "markdown"', configPath);
}
}
// Validate boolean fields
const booleanFields = ['preserveComments', 'strictMode'];
for (const field of booleanFields) {
if (field in config && typeof config[field] !== 'boolean') {
throw new ConfigurationError(`${field} must be a boolean`, configPath);
}
}
// Validate nested objects
const objectFields = ['customOperators', 'customKeywords', 'outputOptions', 'conversionRules'];
for (const field of objectFields) {
if (field in config && (typeof config[field] !== 'object' || config[field] === null)) {
throw new ConfigurationError(`${field} must be an object`, configPath);
}
}
}
/**
* Merge configuration with defaults
*/
export function mergeConfig(userConfig = {}, fileConfig = {}) {
return {
...DEFAULT_CONFIG,
...fileConfig,
...userConfig,
// Deep merge nested objects
customOperators: {
...DEFAULT_CONFIG.customOperators,
...fileConfig.customOperators,
...userConfig.customOperators
},
customKeywords: {
...DEFAULT_CONFIG.customKeywords,
...fileConfig.customKeywords,
...userConfig.customKeywords
},
outputOptions: {
...DEFAULT_CONFIG.outputOptions,
...fileConfig.outputOptions,
...userConfig.outputOptions
},
conversionRules: {
...DEFAULT_CONFIG.conversionRules,
...fileConfig.conversionRules,
...userConfig.conversionRules
}
};
}
/**
* Get final configuration by merging defaults, file config, and user options
*/
export function getConfig(userOptions = {}, configPath) {
const fileConfig = loadConfigFromFile(configPath);
return mergeConfig(userOptions, fileConfig);
}
/**
* Create a sample configuration file
*/
export function createSampleConfig(outputPath = '.python2ibrc') {
const sampleConfig = {
indentSize: 4,
outputFormat: 'plain',
preserveComments: true,
strictMode: false,
customOperators: {
'+=': '← {left} + {right}',
'-=': '← {left} - {right}',
'*=': '← {left} * {right}',
'/=': '← {left} / {right}'
},
customKeywords: {
print: 'OUTPUT',
input: 'INPUT',
len: 'LENGTH',
range: 'RANGE'
},
outputOptions: {
includeLineNumbers: false,
includeComments: true,
wrapInCodeBlock: false
},
conversionRules: {
forceExplicitTypes: false,
convertFStrings: true,
expandCompoundAssignments: true,
simplifyExpressions: false
}
};
writeFileSync(outputPath, JSON.stringify(sampleConfig, null, 2));
}
//# sourceMappingURL=index.js.map