@shohojdhara/atomix 0.5.2 → 0.5.4
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/atomix.config.ts +33 -33
- package/dist/config.d.ts +187 -112
- package/dist/config.js +7 -49
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +1958 -900
- package/dist/index.esm.js +2275 -383
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +2327 -417
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/theme.d.ts +1390 -276
- package/dist/theme.js +2129 -621
- package/dist/theme.js.map +1 -1
- package/package.json +1 -1
- package/scripts/cli/internal/config-loader.js +30 -20
- package/src/lib/config/index.ts +38 -362
- package/src/lib/config/loader.ts +419 -0
- package/src/lib/config/public-api.ts +43 -0
- package/src/lib/config/types.ts +389 -0
- package/src/lib/config/validator.ts +305 -0
- package/src/lib/theme/adapters/index.ts +1 -1
- package/src/lib/theme/adapters/themeAdapter.ts +358 -229
- package/src/lib/theme/components/ThemeToggle.tsx +276 -0
- package/src/lib/theme/config/configLoader.ts +351 -0
- package/src/lib/theme/config/loader.ts +221 -0
- package/src/lib/theme/core/createTheme.ts +126 -50
- package/src/lib/theme/core/createThemeObject.ts +7 -4
- package/src/lib/theme/hooks/useThemeSwitcher.ts +164 -0
- package/src/lib/theme/index.ts +322 -38
- package/src/lib/theme/runtime/ThemeProvider.tsx +44 -10
- package/src/lib/theme/runtime/__tests__/ThemeProvider.test.tsx +44 -393
- package/src/lib/theme/runtime/useTheme.ts +1 -0
- package/src/lib/theme/tokens/tokens.ts +101 -1
- package/src/lib/theme/types.ts +91 -0
- package/src/lib/theme/utils/performanceMonitor.ts +315 -0
- package/src/lib/theme/utils/responsive.ts +280 -0
- package/src/lib/theme/utils/themeUtils.ts +531 -117
- package/src/styles/05-objects/_objects.masonry-grid.scss +3 -3
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Atomix Config Loader
|
|
3
|
+
*
|
|
4
|
+
* Helper functions to load atomix.config.ts from external projects.
|
|
5
|
+
* Now also supports atomix.config.js and atomix.config.json
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { AtomixConfig } from './types';
|
|
9
|
+
import { existsSync } from 'fs';
|
|
10
|
+
import { join } from 'path';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Validate Atomix configuration structure
|
|
14
|
+
*
|
|
15
|
+
* Performs basic validation to catch common configuration errors early.
|
|
16
|
+
* Returns warnings for potential issues.
|
|
17
|
+
*
|
|
18
|
+
* @param config - Configuration object to validate
|
|
19
|
+
* @returns Array of validation warnings (empty if valid)
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* import { loadAtomixConfig, validateConfig } from '@shohojdhara/atomix/config';
|
|
24
|
+
*
|
|
25
|
+
* const config = loadAtomixConfig();
|
|
26
|
+
* const warnings = validateConfig(config);
|
|
27
|
+
* warnings.forEach(w => console.warn(w));
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export function validateConfig(config: AtomixConfig): string[] {
|
|
31
|
+
const warnings: string[] = [];
|
|
32
|
+
|
|
33
|
+
// Check prefix format
|
|
34
|
+
if (config.prefix) {
|
|
35
|
+
if (!/^[a-zA-Z][a-zA-Z0-9-]*$/.test(config.prefix)) {
|
|
36
|
+
warnings.push(
|
|
37
|
+
`Invalid prefix "${config.prefix}". Prefix should start with a letter and contain only letters, numbers, and hyphens.\n` +
|
|
38
|
+
'Example: "myapp", "brand-ui", "enterprise"'
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (config.prefix.length < 2) {
|
|
43
|
+
warnings.push(
|
|
44
|
+
`Prefix "${config.prefix}" is too short. Use at least 2 characters for clarity.\n` +
|
|
45
|
+
'Example: "app" instead of "a"'
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Check theme structure
|
|
51
|
+
if (config.theme) {
|
|
52
|
+
// Warn if both extend and tokens are provided
|
|
53
|
+
if (config.theme.extend && config.theme.tokens) {
|
|
54
|
+
warnings.push(
|
|
55
|
+
'Both theme.extend and theme.tokens are defined. theme.tokens will take precedence and completely replace the default token system.\n' +
|
|
56
|
+
'If you want to extend defaults, remove theme.tokens and use only theme.extend.'
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Check extend structure
|
|
61
|
+
if (config.theme.extend) {
|
|
62
|
+
const extend = config.theme.extend;
|
|
63
|
+
|
|
64
|
+
// Check for common typos in theme properties
|
|
65
|
+
const validThemeKeys = [
|
|
66
|
+
'colors', 'typography', 'spacing', 'borderRadius',
|
|
67
|
+
'shadows', 'zIndex', 'transitions', 'breakpoints'
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
Object.keys(extend).forEach(key => {
|
|
71
|
+
if (!validThemeKeys.includes(key)) {
|
|
72
|
+
warnings.push(
|
|
73
|
+
`Unknown theme property: "${key}"\n` +
|
|
74
|
+
`Valid properties: ${validThemeKeys.join(', ')}\n` +
|
|
75
|
+
'Did you mean one of these? Check for typos.'
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Validate advanced features
|
|
83
|
+
if (config.interactiveEffects) {
|
|
84
|
+
const ie = config.interactiveEffects;
|
|
85
|
+
|
|
86
|
+
// Validate vortex settings
|
|
87
|
+
if (ie.vortex) {
|
|
88
|
+
if (ie.vortex.strength && (ie.vortex.strength < 0 || ie.vortex.strength > 10)) {
|
|
89
|
+
warnings.push('Vortex strength should be between 0 and 10 for optimal performance');
|
|
90
|
+
}
|
|
91
|
+
if (ie.vortex.radius && ie.vortex.radius < 0) {
|
|
92
|
+
warnings.push('Vortex radius should be a positive number');
|
|
93
|
+
}
|
|
94
|
+
if (ie.vortex.decay && (ie.vortex.decay <= 0 || ie.vortex.decay > 1)) {
|
|
95
|
+
warnings.push('Vortex decay should be between 0 and 1');
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Validate chromatic aberration settings
|
|
100
|
+
if (ie.chromaticAberration) {
|
|
101
|
+
if (ie.chromaticAberration.redShift && Math.abs(ie.chromaticAberration.redShift) > 0.1) {
|
|
102
|
+
warnings.push('Chromatic red shift value seems unusually high (>0.1), verify this is intended');
|
|
103
|
+
}
|
|
104
|
+
if (ie.chromaticAberration.blueShift && Math.abs(ie.chromaticAberration.blueShift) > 0.1) {
|
|
105
|
+
warnings.push('Chromatic blue shift value seems unusually high (>0.1), verify this is intended');
|
|
106
|
+
}
|
|
107
|
+
if (ie.chromaticAberration.edgeThreshold && (ie.chromaticAberration.edgeThreshold < 0 || ie.chromaticAberration.edgeThreshold > 1)) {
|
|
108
|
+
warnings.push('Chromatic edge threshold should be between 0 and 1');
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Validate mouse interaction settings
|
|
113
|
+
if (ie.mouseInteraction) {
|
|
114
|
+
if (ie.mouseInteraction.sensitivity && ie.mouseInteraction.sensitivity < 0) {
|
|
115
|
+
warnings.push('Mouse sensitivity should be a positive number');
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Validate animation speed settings
|
|
120
|
+
if (ie.animationSpeed) {
|
|
121
|
+
if (ie.animationSpeed.base && ie.animationSpeed.base <= 0) {
|
|
122
|
+
warnings.push('Animation base speed should be greater than 0');
|
|
123
|
+
}
|
|
124
|
+
if (ie.animationSpeed.timeMultiplier && ie.animationSpeed.timeMultiplier <= 0) {
|
|
125
|
+
warnings.push('Animation time multiplier should be greater than 0');
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Validate optimization settings
|
|
131
|
+
if (config.optimization) {
|
|
132
|
+
const opt = config.optimization;
|
|
133
|
+
|
|
134
|
+
// Validate responsive breakpoints
|
|
135
|
+
if (opt.responsive && opt.responsive.breakpoints) {
|
|
136
|
+
const breakpoints = opt.responsive.breakpoints;
|
|
137
|
+
if (breakpoints.mobile && !isValidCSSLength(breakpoints.mobile)) {
|
|
138
|
+
warnings.push('Mobile breakpoint value is not a valid CSS length');
|
|
139
|
+
}
|
|
140
|
+
if (breakpoints.tablet && !isValidCSSLength(breakpoints.tablet)) {
|
|
141
|
+
warnings.push('Tablet breakpoint value is not a valid CSS length');
|
|
142
|
+
}
|
|
143
|
+
if (breakpoints.desktop && !isValidCSSLength(breakpoints.desktop)) {
|
|
144
|
+
warnings.push('Desktop breakpoint value is not a valid CSS length');
|
|
145
|
+
}
|
|
146
|
+
if (breakpoints.wide && !isValidCSSLength(breakpoints.wide)) {
|
|
147
|
+
warnings.push('Wide breakpoint value is not a valid CSS length');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Validate device scaling
|
|
152
|
+
if (opt.responsive && opt.responsive.deviceScaling) {
|
|
153
|
+
const scaling = opt.responsive.deviceScaling;
|
|
154
|
+
if (scaling.mobile && (scaling.mobile <= 0 || scaling.mobile > 1)) {
|
|
155
|
+
warnings.push('Mobile device scaling should be between 0 and 1');
|
|
156
|
+
}
|
|
157
|
+
if (scaling.tablet && (scaling.tablet <= 0 || scaling.tablet > 1)) {
|
|
158
|
+
warnings.push('Tablet device scaling should be between 0 and 1');
|
|
159
|
+
}
|
|
160
|
+
if (scaling.desktop && (scaling.desktop <= 0 || scaling.desktop > 1)) {
|
|
161
|
+
warnings.push('Desktop device scaling should be between 0 and 1');
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Validate performance settings
|
|
166
|
+
if (opt.performance) {
|
|
167
|
+
if (opt.performance.fpsTarget && (opt.performance.fpsTarget <= 0 || opt.performance.fpsTarget > 240)) {
|
|
168
|
+
warnings.push('FPS target should be a reasonable value (typically 30-120)');
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Validate auto-scaling thresholds
|
|
173
|
+
if (opt.autoScaling && opt.autoScaling.qualityThresholds) {
|
|
174
|
+
const thresholds = opt.autoScaling.qualityThresholds;
|
|
175
|
+
if (thresholds.lowEnd && (thresholds.lowEnd < 0 || thresholds.lowEnd > 1)) {
|
|
176
|
+
warnings.push('Auto-scaling low-end threshold should be between 0 and 1');
|
|
177
|
+
}
|
|
178
|
+
if (thresholds.midRange && (thresholds.midRange < 0 || thresholds.midRange > 1)) {
|
|
179
|
+
warnings.push('Auto-scaling mid-range threshold should be between 0 and 1');
|
|
180
|
+
}
|
|
181
|
+
if (thresholds.highEnd && (thresholds.highEnd < 0 || thresholds.highEnd > 1)) {
|
|
182
|
+
warnings.push('Auto-scaling high-end threshold should be between 0 and 1');
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Validate visual polish settings
|
|
188
|
+
if (config.visualPolish) {
|
|
189
|
+
const vp = config.visualPolish;
|
|
190
|
+
|
|
191
|
+
// Validate content aware blur settings
|
|
192
|
+
if (vp.contentAwareBlur) {
|
|
193
|
+
if (vp.contentAwareBlur.edgePreservation !== undefined && typeof vp.contentAwareBlur.edgePreservation !== 'boolean') {
|
|
194
|
+
warnings.push('Content-aware blur edge preservation should be a boolean value');
|
|
195
|
+
}
|
|
196
|
+
if (vp.contentAwareBlur.depthDetection !== undefined && typeof vp.contentAwareBlur.depthDetection !== 'boolean') {
|
|
197
|
+
warnings.push('Content-aware blur depth detection should be a boolean value');
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Validate holographic effects settings
|
|
202
|
+
if (vp.holographicEffects) {
|
|
203
|
+
if (vp.holographicEffects.enabled !== undefined && typeof vp.holographicEffects.enabled !== 'boolean') {
|
|
204
|
+
warnings.push('Holographic effects enabled should be a boolean value');
|
|
205
|
+
}
|
|
206
|
+
if (vp.holographicEffects.rainbowDiffraction !== undefined && typeof vp.holographicEffects.rainbowDiffraction !== 'boolean') {
|
|
207
|
+
warnings.push('Holographic rainbow diffraction should be a boolean value');
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Validate AI settings
|
|
213
|
+
if (config.ai) {
|
|
214
|
+
if (config.ai.provider && !['openai', 'anthropic'].includes(config.ai.provider)) {
|
|
215
|
+
warnings.push(`Unknown AI provider: "${config.ai.provider}". Supported: openai, anthropic`);
|
|
216
|
+
}
|
|
217
|
+
if (config.ai.temperature && (config.ai.temperature < 0 || config.ai.temperature > 1)) {
|
|
218
|
+
warnings.push('AI temperature should be between 0 and 1');
|
|
219
|
+
}
|
|
220
|
+
if (config.ai.maxTokens && config.ai.maxTokens < 100) {
|
|
221
|
+
warnings.push('AI maxTokens should typically be 100 or more');
|
|
222
|
+
}
|
|
223
|
+
if (config.ai.rateLimit) {
|
|
224
|
+
if (config.ai.rateLimit.requests <= 0) {
|
|
225
|
+
warnings.push('AI rate limit requests should be greater than 0');
|
|
226
|
+
}
|
|
227
|
+
if (config.ai.rateLimit.windowMs <= 0) {
|
|
228
|
+
warnings.push('AI rate limit window should be greater than 0');
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Validate telemetry settings
|
|
234
|
+
if (config.telemetry) {
|
|
235
|
+
if (config.telemetry.path && !config.telemetry.path.endsWith('.json')) {
|
|
236
|
+
warnings.push('Telemetry path should typically end with .json');
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return warnings;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Helper function to validate CSS length values
|
|
245
|
+
*/
|
|
246
|
+
function isValidCSSLength(value: string): boolean {
|
|
247
|
+
// Basic validation for CSS length values
|
|
248
|
+
const cssLengthRegex = /^(\d+(\.\d+)?)(px|em|rem|%|vw|vh|vmin|vmax|cm|mm|in|pt|pc|ex|ch)?$/;
|
|
249
|
+
return cssLengthRegex.test(value);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Load Atomix configuration from project root
|
|
254
|
+
*
|
|
255
|
+
* Attempts to load atomix.config.ts, atomix.config.js, or atomix.config.json from the current working directory.
|
|
256
|
+
* Falls back to default config if file doesn't exist.
|
|
257
|
+
*
|
|
258
|
+
* @param options - Loader options
|
|
259
|
+
* @returns Loaded configuration or default
|
|
260
|
+
*
|
|
261
|
+
* @example
|
|
262
|
+
* ```typescript
|
|
263
|
+
* import { loadAtomixConfig } from '@shohojdhara/atomix/config';
|
|
264
|
+
* import { createTheme } from '@shohojdhara/atomix/theme';
|
|
265
|
+
*
|
|
266
|
+
* const config = loadAtomixConfig();
|
|
267
|
+
* const theme = createTheme(config.theme?.tokens || {});
|
|
268
|
+
* ```
|
|
269
|
+
*/
|
|
270
|
+
export function loadAtomixConfig(
|
|
271
|
+
options: {
|
|
272
|
+
/** Custom config path (default: 'atomix.config.ts') */
|
|
273
|
+
configPath?: string;
|
|
274
|
+
/** Whether to throw error if config not found (default: false) */
|
|
275
|
+
required?: boolean;
|
|
276
|
+
} = {}
|
|
277
|
+
): AtomixConfig {
|
|
278
|
+
const { configPath, required = false } = options;
|
|
279
|
+
|
|
280
|
+
// Default config
|
|
281
|
+
const defaultConfig: AtomixConfig = {
|
|
282
|
+
prefix: 'atomix',
|
|
283
|
+
theme: {
|
|
284
|
+
extend: {},
|
|
285
|
+
},
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
// In browser environments, config loading is not supported
|
|
289
|
+
if (typeof window !== 'undefined') {
|
|
290
|
+
if (required) {
|
|
291
|
+
throw new Error(
|
|
292
|
+
'Config loading requires Node.js file system access.\n' +
|
|
293
|
+
'\n' +
|
|
294
|
+
'Solutions:\n' +
|
|
295
|
+
'1. Provide tokens explicitly to createTheme():\n' +
|
|
296
|
+
' const css = createTheme({ "--brand-primary": "#6366f1" });\n' +
|
|
297
|
+
'\n' +
|
|
298
|
+
'2. Use SSR framework (Next.js, Remix, Astro)\n' +
|
|
299
|
+
'\n' +
|
|
300
|
+
'3. Load config on server and pass to client\n' +
|
|
301
|
+
'\n' +
|
|
302
|
+
'See examples/config-examples/browser-only.config.ts'
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
return defaultConfig;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// If a specific config path is provided, try to load it directly
|
|
309
|
+
if (configPath) {
|
|
310
|
+
return loadConfigAtPath(configPath, required, defaultConfig);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Otherwise, try standard locations in order of preference
|
|
314
|
+
const possiblePaths = [
|
|
315
|
+
'atomix.config.ts',
|
|
316
|
+
'atomix.config.js',
|
|
317
|
+
'atomix.config.json'
|
|
318
|
+
];
|
|
319
|
+
|
|
320
|
+
for (const path of possiblePaths) {
|
|
321
|
+
const config = loadConfigAtPath(path, false, defaultConfig);
|
|
322
|
+
// If we found a valid config, return it
|
|
323
|
+
if (JSON.stringify(config) !== JSON.stringify(defaultConfig)) {
|
|
324
|
+
return config;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// If no config file was found or all contained only defaults, return default config
|
|
329
|
+
if (required) {
|
|
330
|
+
throw new Error(
|
|
331
|
+
`No Atomix configuration file found in project root.\n` +
|
|
332
|
+
'\n' +
|
|
333
|
+
'Expected one of:\n' +
|
|
334
|
+
' - atomix.config.ts (recommended)\n' +
|
|
335
|
+
' - atomix.config.js\n' +
|
|
336
|
+
' - atomix.config.json\n' +
|
|
337
|
+
'\n' +
|
|
338
|
+
'Quick Fix:\n' +
|
|
339
|
+
'1. Create a config file in your project root:\n' +
|
|
340
|
+
' touch atomix.config.ts\n' +
|
|
341
|
+
'\n' +
|
|
342
|
+
'2. Add basic configuration:\n' +
|
|
343
|
+
' import { defineConfig } from "@shohojdhara/atomix/config";\n' +
|
|
344
|
+
' export default defineConfig({ prefix: "myapp" });\n' +
|
|
345
|
+
'\n' +
|
|
346
|
+
'3. Or copy an example:\n' +
|
|
347
|
+
' cp node_modules/@shohojdhara/atomix/examples/config-examples/standard.config.ts ./atomix.config.ts'
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
return defaultConfig;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Helper function to load config from a specific path
|
|
356
|
+
*/
|
|
357
|
+
function loadConfigAtPath(path: string, required: boolean, defaultConfig: AtomixConfig): AtomixConfig {
|
|
358
|
+
try {
|
|
359
|
+
// Use dynamic import for ESM compatibility
|
|
360
|
+
const configModule = require(path);
|
|
361
|
+
const config = configModule.default || configModule;
|
|
362
|
+
|
|
363
|
+
// Validate it's an AtomixConfig
|
|
364
|
+
if (config && typeof config === 'object') {
|
|
365
|
+
return config as AtomixConfig;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
throw new Error('Invalid config format');
|
|
369
|
+
} catch (error: any) {
|
|
370
|
+
if (required) {
|
|
371
|
+
throw new Error(`Failed to load config from ${path}: ${error.message}`);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Return default config if not required
|
|
375
|
+
return defaultConfig;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Resolve config path
|
|
381
|
+
*
|
|
382
|
+
* Finds atomix.config.ts in the project, checking common locations.
|
|
383
|
+
* Returns null in browser environments where file system access is not available.
|
|
384
|
+
*
|
|
385
|
+
* This function is designed to help tools identify if a config exists without loading it.
|
|
386
|
+
*
|
|
387
|
+
* @param configPath - Optional custom path to check
|
|
388
|
+
* @returns Absolute path to config file or null if not found
|
|
389
|
+
*/
|
|
390
|
+
export function resolveConfigPath(configPath?: string): string | null {
|
|
391
|
+
// In browser environments, config resolution is not possible
|
|
392
|
+
if (typeof window !== 'undefined') {
|
|
393
|
+
return null;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// If a specific config path is provided, check if it exists
|
|
397
|
+
if (configPath) {
|
|
398
|
+
const absPath = join(process.cwd(), configPath);
|
|
399
|
+
if (existsSync(absPath)) {
|
|
400
|
+
return absPath;
|
|
401
|
+
}
|
|
402
|
+
return null;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Otherwise, check standard locations
|
|
406
|
+
const possiblePaths = [
|
|
407
|
+
join(process.cwd(), 'atomix.config.ts'),
|
|
408
|
+
join(process.cwd(), 'atomix.config.js'),
|
|
409
|
+
join(process.cwd(), 'atomix.config.json')
|
|
410
|
+
];
|
|
411
|
+
|
|
412
|
+
for (const path of possiblePaths) {
|
|
413
|
+
if (existsSync(path)) {
|
|
414
|
+
return path;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return null;
|
|
419
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public API for loading and managing Atomix configuration
|
|
3
|
+
*
|
|
4
|
+
* This module provides the public-facing API for configuration loading
|
|
5
|
+
* in external projects.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { AtomixConfig } from './types';
|
|
9
|
+
import { loadAtomixConfig as internalLoadConfig, validateConfig as internalValidateConfig } from './loader';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Load Atomix configuration from an external project.
|
|
13
|
+
*
|
|
14
|
+
* @param options - Loading options
|
|
15
|
+
* @returns The loaded configuration
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* import { loadConfig } from '@shohojdhara/atomix/config';
|
|
20
|
+
*
|
|
21
|
+
* const config = loadConfig();
|
|
22
|
+
* console.log(config.prefix); // 'atomix' or user's custom prefix
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export function loadConfig(options?: {
|
|
26
|
+
configPath?: string;
|
|
27
|
+
required?: boolean;
|
|
28
|
+
}): AtomixConfig {
|
|
29
|
+
return internalLoadConfig({
|
|
30
|
+
configPath: options?.configPath,
|
|
31
|
+
required: options?.required ?? false,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Validate Atomix configuration structure.
|
|
37
|
+
*
|
|
38
|
+
* @param config - Configuration object to validate
|
|
39
|
+
* @returns Array of validation warnings (empty if valid)
|
|
40
|
+
*/
|
|
41
|
+
export function validateConfig(config: AtomixConfig): string[] {
|
|
42
|
+
return internalValidateConfig(config);
|
|
43
|
+
}
|