|
1 | | -import fs from 'fs'; |
2 | | -import path from 'path'; |
3 | | -import { TypeGeneratorOptions, defaultTypeGeneratorOptions } from '../generators/typescript.js'; |
| 1 | +import * as fs from 'fs'; |
| 2 | +import * as path from 'path'; |
4 | 3 |
|
| 4 | +/** |
| 5 | + * LuaTS Configuration interface |
| 6 | + */ |
5 | 7 | export interface LuatsConfig { |
6 | | - // TypeScript generator options |
7 | | - typeGeneratorOptions: TypeGeneratorOptions; |
| 8 | + // Input/output configuration |
| 9 | + input?: string; |
| 10 | + output?: string; |
| 11 | + |
| 12 | + // Processing options |
| 13 | + include?: string[]; |
| 14 | + exclude?: string[]; |
8 | 15 |
|
9 | | - // File patterns |
10 | | - include: string[]; |
11 | | - exclude: string[]; |
| 16 | + // Parser options |
| 17 | + parserOptions?: { |
| 18 | + luaVersion?: '5.1' | '5.2' | '5.3' | '5.4' | 'luau'; |
| 19 | + locations?: boolean; |
| 20 | + comments?: boolean; |
| 21 | + scope?: boolean; |
| 22 | + }; |
12 | 23 |
|
13 | | - // Output options |
14 | | - outDir: string | null; |
15 | | - preserveDirectoryStructure: boolean; |
| 24 | + // Formatter options |
| 25 | + formatterOptions?: { |
| 26 | + indentSize?: number; |
| 27 | + lineWidth?: number; |
| 28 | + useTabs?: boolean; |
| 29 | + newLineAtEnd?: boolean; |
| 30 | + }; |
16 | 31 |
|
17 | | - // Plugin support |
18 | | - plugins: string[]; |
| 32 | + // Type generator options |
| 33 | + typeGeneratorOptions?: { |
| 34 | + moduleType?: 'esm' | 'commonjs'; |
| 35 | + inferTypes?: boolean; |
| 36 | + strictNullChecks?: boolean; |
| 37 | + robloxTypes?: boolean; |
| 38 | + }; |
19 | 39 |
|
20 | | - // Comment processing |
21 | | - preserveComments: boolean; |
22 | | - commentStyle: 'jsdoc' | 'inline' | 'both'; |
| 40 | + // Plugin configuration |
| 41 | + plugins?: string[]; |
23 | 42 |
|
24 | | - // Type inference options |
25 | | - inferTypes: boolean; |
26 | | - mergeInterfaces: boolean; |
| 43 | + // Logging options |
| 44 | + verbose?: boolean; |
27 | 45 | } |
28 | 46 |
|
| 47 | +/** |
| 48 | + * Default configuration values |
| 49 | + */ |
29 | 50 | export const defaultConfig: LuatsConfig = { |
30 | | - typeGeneratorOptions: defaultTypeGeneratorOptions, |
31 | 51 | include: ['**/*.{lua,luau}'], |
32 | 52 | exclude: ['**/node_modules/**', '**/dist/**'], |
33 | | - outDir: null, // Same as input if null |
34 | | - preserveDirectoryStructure: true, |
| 53 | + |
| 54 | + parserOptions: { |
| 55 | + luaVersion: '5.1', |
| 56 | + locations: true, |
| 57 | + comments: true, |
| 58 | + scope: true |
| 59 | + }, |
| 60 | + |
| 61 | + formatterOptions: { |
| 62 | + indentSize: 2, |
| 63 | + lineWidth: 80, |
| 64 | + useTabs: false, |
| 65 | + newLineAtEnd: true |
| 66 | + }, |
| 67 | + |
| 68 | + typeGeneratorOptions: { |
| 69 | + moduleType: 'esm', |
| 70 | + inferTypes: true, |
| 71 | + strictNullChecks: true, |
| 72 | + robloxTypes: false |
| 73 | + }, |
| 74 | + |
35 | 75 | plugins: [], |
36 | | - preserveComments: true, |
37 | | - commentStyle: 'jsdoc', |
38 | | - inferTypes: false, |
39 | | - mergeInterfaces: true |
| 76 | + |
| 77 | + verbose: false |
40 | 78 | }; |
41 | 79 |
|
42 | 80 | /** |
43 | | - * Load configuration from a file, with fallbacks |
| 81 | + * Configuration file names to look for |
| 82 | + */ |
| 83 | +const CONFIG_FILE_NAMES = [ |
| 84 | + '.luatsrc', |
| 85 | + '.luatsrc.json', |
| 86 | + '.luatsrc.js', |
| 87 | + 'luats.config.js', |
| 88 | + 'luats.config.json' |
| 89 | +]; |
| 90 | + |
| 91 | +/** |
| 92 | + * Load configuration from file |
44 | 93 | */ |
45 | 94 | export async function loadConfig(configPath?: string): Promise<LuatsConfig> { |
46 | | - // Try to find the config file |
47 | | - const filePath = configPath ? path.resolve(configPath) : findConfigFile(); |
48 | | - |
49 | | - // Start with the default config |
50 | | - let config: LuatsConfig = { ...defaultConfig }; |
| 95 | + // If config path is specified, try to load it |
| 96 | + if (configPath) { |
| 97 | + if (!fs.existsSync(configPath)) { |
| 98 | + throw new Error(`Config file not found: ${configPath}`); |
| 99 | + } |
| 100 | + return loadConfigFile(configPath); |
| 101 | + } |
51 | 102 |
|
52 | | - // Load from file if found |
53 | | - if (filePath && fs.existsSync(filePath)) { |
54 | | - try { |
55 | | - const fileContent = fs.readFileSync(filePath, 'utf-8'); |
56 | | - const fileConfig = JSON.parse(fileContent); |
57 | | - |
58 | | - // Merge configs, ensuring defaults for any missing properties |
59 | | - config = mergeConfigs(config, fileConfig); |
60 | | - |
61 | | - console.log(`Loaded configuration from ${filePath}`); |
62 | | - } catch (error) { |
63 | | - console.warn(`Error loading config from ${filePath}:`, error); |
64 | | - console.warn('Using default configuration'); |
| 103 | + // Otherwise search for config files |
| 104 | + for (const fileName of CONFIG_FILE_NAMES) { |
| 105 | + const filePath = path.resolve(process.cwd(), fileName); |
| 106 | + if (fs.existsSync(filePath)) { |
| 107 | + return loadConfigFile(filePath); |
65 | 108 | } |
66 | | - } else if (configPath) { |
67 | | - // Only warn if a specific path was provided but not found |
68 | | - console.warn(`Config file not found: ${configPath}`); |
69 | | - console.warn('Using default configuration'); |
70 | 109 | } |
71 | 110 |
|
72 | | - return config; |
| 111 | + // Return default config if no config file found |
| 112 | + return { ...defaultConfig }; |
73 | 113 | } |
74 | 114 |
|
75 | 115 | /** |
76 | | - * Find a configuration file in the current or parent directories |
| 116 | + * Load and parse a configuration file |
77 | 117 | */ |
78 | | -function findConfigFile(): string | null { |
79 | | - const configNames = ['luats.config.json', '.luatsrc.json', '.luatsrc']; |
80 | | - let currentDir = process.cwd(); |
| 118 | +async function loadConfigFile(filePath: string): Promise<LuatsConfig> { |
| 119 | + const ext = path.extname(filePath); |
81 | 120 |
|
82 | | - // Try to find config in current dir or any parent dir |
83 | | - while (true) { |
84 | | - for (const name of configNames) { |
85 | | - const configPath = path.join(currentDir, name); |
86 | | - if (fs.existsSync(configPath)) { |
87 | | - return configPath; |
88 | | - } |
| 121 | + try { |
| 122 | + if (ext === '.js') { |
| 123 | + // For JS files, require the module |
| 124 | + const config = require(filePath); |
| 125 | + return mergeWithDefaultConfig(config); |
| 126 | + } else { |
| 127 | + // For JSON files, read and parse |
| 128 | + const content = fs.readFileSync(filePath, 'utf-8'); |
| 129 | + const config = JSON.parse(content); |
| 130 | + return mergeWithDefaultConfig(config); |
89 | 131 | } |
90 | | - |
91 | | - // Go up one directory |
92 | | - const parentDir = path.dirname(currentDir); |
93 | | - if (parentDir === currentDir) { |
94 | | - // We've reached the root |
95 | | - break; |
96 | | - } |
97 | | - currentDir = parentDir; |
| 132 | + } catch (error) { |
| 133 | + throw new Error(`Failed to load config file ${filePath}: ${(error as Error).message}`); |
98 | 134 | } |
99 | | - |
100 | | - return null; |
101 | 135 | } |
102 | 136 |
|
103 | 137 | /** |
104 | | - * Merge configurations, preserving defaults for missing properties |
| 138 | + * Merge user config with default config |
105 | 139 | */ |
106 | | -function mergeConfigs(baseConfig: LuatsConfig, userConfig: Partial<LuatsConfig>): LuatsConfig { |
107 | | - // Deep merge of the configs |
108 | | - const result: LuatsConfig = { ...baseConfig }; |
109 | | - |
110 | | - // Handle top-level properties |
111 | | - Object.keys(userConfig).forEach(key => { |
112 | | - const typedKey = key as keyof LuatsConfig; |
113 | | - const userValue = userConfig[typedKey]; |
114 | | - |
115 | | - // Special handling for objects that need deep merging |
116 | | - if (typedKey === 'typeGeneratorOptions' && userValue) { |
117 | | - result.typeGeneratorOptions = { |
118 | | - ...baseConfig.typeGeneratorOptions, |
119 | | - ...(userValue as Partial<TypeGeneratorOptions>) |
120 | | - }; |
121 | | - } else if (userValue !== undefined) { |
122 | | - // For other properties, use the user value if defined |
123 | | - (result as any)[key] = userValue; |
| 140 | +function mergeWithDefaultConfig(userConfig: LuatsConfig): LuatsConfig { |
| 141 | + return { |
| 142 | + ...defaultConfig, |
| 143 | + ...userConfig, |
| 144 | + parserOptions: { |
| 145 | + ...defaultConfig.parserOptions, |
| 146 | + ...userConfig.parserOptions |
| 147 | + }, |
| 148 | + formatterOptions: { |
| 149 | + ...defaultConfig.formatterOptions, |
| 150 | + ...userConfig.formatterOptions |
| 151 | + }, |
| 152 | + typeGeneratorOptions: { |
| 153 | + ...defaultConfig.typeGeneratorOptions, |
| 154 | + ...userConfig.typeGeneratorOptions |
124 | 155 | } |
125 | | - }); |
126 | | - |
127 | | - return result; |
128 | | -} |
| 156 | + }; |
129 | 157 | } |
0 commit comments