styles-config 2.0.0-alpha.1

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/lib/options.js ADDED
@@ -0,0 +1,128 @@
1
+ import picomatch from 'picomatch';
2
+ import path from 'path';
3
+ /**
4
+ * Map of file extensions to language keys
5
+ */
6
+ const extensionToLanguage = new Map([
7
+ ['.less', 'less'],
8
+ ['.scss', 'scss'],
9
+ ['.sass', 'scss'],
10
+ ['.jess', 'jess'],
11
+ ['.css', 'css']
12
+ ]);
13
+ /**
14
+ * Infer language from a file path's extension
15
+ */
16
+ function inferLanguage(filePath) {
17
+ if (!filePath) {
18
+ return undefined;
19
+ }
20
+ const ext = path.extname(filePath).toLowerCase();
21
+ return extensionToLanguage.get(ext);
22
+ }
23
+ /**
24
+ * Check if a file path matches a pattern (exact path, relative path, or glob)
25
+ */
26
+ function matchesFile(pattern, filePath) {
27
+ if (!pattern || !filePath) {
28
+ return false;
29
+ }
30
+ // Normalize paths for comparison
31
+ const normalizedPattern = path.normalize(pattern);
32
+ const normalizedFile = path.normalize(filePath);
33
+ // Try exact match first
34
+ if (normalizedPattern === normalizedFile) {
35
+ return true;
36
+ }
37
+ // Try basename match (e.g., pattern "styles.less" matches "/path/to/styles.less")
38
+ if (path.basename(normalizedFile) === normalizedPattern) {
39
+ return true;
40
+ }
41
+ // Try glob/pattern match using picomatch
42
+ const isMatch = picomatch(pattern, { dot: true });
43
+ return isMatch(filePath) || isMatch(normalizedFile);
44
+ }
45
+ /**
46
+ * Get matching options from an array of file-based options.
47
+ * Returns merged options from:
48
+ * 1. All entries without a `file` property (defaults)
49
+ * 2. All entries whose `file` pattern matches the given path
50
+ *
51
+ * Later entries override earlier ones.
52
+ */
53
+ function getMatchingOptions(options, filePath) {
54
+ if (!options) {
55
+ return {};
56
+ }
57
+ const optionsArray = Array.isArray(options) ? options : [options];
58
+ let result = {};
59
+ for (const opt of optionsArray) {
60
+ // Include if: no file pattern (default), or file pattern matches
61
+ if (!opt.file || (filePath && matchesFile(opt.file, filePath))) {
62
+ // Merge this entry's options, excluding the 'file' property
63
+ const rest = { ...opt };
64
+ delete rest.file;
65
+ result = { ...result, ...rest };
66
+ }
67
+ }
68
+ return result;
69
+ }
70
+ /**
71
+ * Get merged options by combining compile, language, input, and output settings.
72
+ *
73
+ * Merge priority (later wins):
74
+ * 1. compile options (base)
75
+ * 2. language-specific options (inferred from input extension or explicitly specified)
76
+ * 3. matched input options (if input path provided and matches)
77
+ * 4. matched output options (if output path provided and matches)
78
+ *
79
+ * @param config - The styles configuration object
80
+ * @param params - Options specifying language, input file, and output file
81
+ * @returns Merged options object
82
+ *
83
+ * @example
84
+ * // Get Less options for a specific input/output (language inferred from .less extension)
85
+ * const options = getOptions(config, {
86
+ * input: 'src/styles/main.less',
87
+ * output: 'dist/main.css'
88
+ * });
89
+ *
90
+ * @example
91
+ * // Explicitly specify language
92
+ * const options = getOptions(config, { language: 'less' });
93
+ *
94
+ * @example
95
+ * // Get base options without language-specific settings
96
+ * const options = getOptions(config);
97
+ */
98
+ export function getOptions(config = {}, params = {}) {
99
+ const { input: inputFile, output: outputFile } = params;
100
+ const { compile = {}, input, output, language: languageConfig = {} } = config;
101
+ // Determine language: explicit param > inferred from input extension
102
+ const language = params.language ?? inferLanguage(inputFile);
103
+ // Get language-specific options if language is determined
104
+ const languageOptions = language ? (languageConfig[language] ?? {}) : {};
105
+ // Get matched input and output options
106
+ const matchedInput = getMatchingOptions(input, inputFile);
107
+ const matchedOutput = getMatchingOptions(output, outputFile);
108
+ // Build result with proper merge priority:
109
+ // 1. compile (base)
110
+ // 2. language-specific
111
+ // 3. matched input
112
+ // 4. matched output
113
+ return {
114
+ // Start with compile-level settings
115
+ mathMode: compile.mathMode,
116
+ unitMode: compile.unitMode,
117
+ equalityMode: compile.equalityMode,
118
+ paths: compile.searchPaths,
119
+ javascriptEnabled: compile.enableJavaScript,
120
+ // Override with language-specific settings
121
+ ...languageOptions,
122
+ // Override with matched input settings
123
+ ...matchedInput,
124
+ // Override with matched output settings
125
+ ...matchedOutput
126
+ };
127
+ }
128
+ //# sourceMappingURL=options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"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"}
package/lib/types.d.ts ADDED
@@ -0,0 +1,320 @@
1
+ /**
2
+ * Math processing modes
3
+ */
4
+ export type MathMode = 'always' | 'parens-division' | 'parens' | 'strict';
5
+ /**
6
+ * Unit conversion modes
7
+ */
8
+ export type UnitMode = 'loose' | 'preserve' | 'strict';
9
+ /**
10
+ * Equality/coercion modes for guard comparisons.
11
+ */
12
+ export type EqualityMode = 'coerce' | 'strict';
13
+ export interface JavaScriptSandboxConfig {
14
+ /**
15
+ * Allow network access for script execution runtime.
16
+ * @default false
17
+ */
18
+ allowHttp?: boolean;
19
+ /**
20
+ * Optional host allowlist when `allowHttp` is enabled.
21
+ */
22
+ allowNetHosts?: string[];
23
+ /**
24
+ * Optional explicit filesystem root for script reads.
25
+ * If omitted, compiler resolves using entry/config roots.
26
+ */
27
+ jsReadRoot?: string;
28
+ }
29
+ export type CompileJavaScriptOption = true | JavaScriptSandboxConfig;
30
+ /**
31
+ * Less compiler options
32
+ * Based on less.js default-options.js and bin/lessc
33
+ */
34
+ export interface LessOptions {
35
+ /**
36
+ * Inline Javascript - @plugin still allowed
37
+ * @default false
38
+ */
39
+ javascriptEnabled?: boolean;
40
+ /**
41
+ * Outputs a makefile import dependency list to stdout.
42
+ * @default false
43
+ */
44
+ depends?: boolean;
45
+ /**
46
+ * @deprecated Compress using less built-in compression.
47
+ * This does an okay job but does not utilise all the tricks of
48
+ * dedicated css compression.
49
+ * @default false
50
+ */
51
+ compress?: boolean;
52
+ /**
53
+ * Runs the less parser and just reports errors without any output.
54
+ * @default false
55
+ */
56
+ lint?: boolean;
57
+ /**
58
+ * Sets available include paths.
59
+ * If the file in an @import rule does not exist at that exact location,
60
+ * less will look for it at the location(s) passed to this option.
61
+ * @default []
62
+ */
63
+ paths?: string[];
64
+ /**
65
+ * Color output in the terminal
66
+ * @default true
67
+ */
68
+ color?: boolean;
69
+ /**
70
+ * @deprecated This option has confusing behavior and may be removed in a future version.
71
+ *
72
+ * Controls how @import statements for .less files are handled inside selector blocks (rulesets).
73
+ *
74
+ * Behavior:
75
+ * - @import at root level: Always processed
76
+ * - @import inside @-rules (@media, @supports, etc.): Processed (these are not selector blocks)
77
+ * - @import inside selector blocks (.class, #id, etc.): Behavior depends on this option
78
+ *
79
+ * Options:
80
+ * - `false` (default): All @import statements are processed regardless of context.
81
+ * - `true`: @import statements inside selector blocks are silently ignored and not output.
82
+ * - `'error'`: @import statements inside selector blocks will throw an error instead of being silently ignored.
83
+ *
84
+ * Note: Only affects .less file imports. CSS imports (url(...) or .css files) are
85
+ * always output as CSS @import statements regardless of this setting.
86
+ *
87
+ * @see https://github.com/less/less.js/issues/656
88
+ * @default false
89
+ */
90
+ strictImports?: boolean | 'error';
91
+ /**
92
+ * Allow Imports from Insecure HTTPS Hosts
93
+ * @default false
94
+ */
95
+ insecure?: boolean;
96
+ /**
97
+ * Allows you to add a path to every generated import and url in your css.
98
+ * This does not affect less import statements that are processed, just ones
99
+ * that are left in the output css.
100
+ * @default ''
101
+ */
102
+ rootpath?: string;
103
+ /**
104
+ * By default URLs are kept as-is, so if you import a file in a sub-directory
105
+ * that references an image, exactly the same URL will be output in the css.
106
+ * This option allows you to re-write URL's in imported files so that the
107
+ * URL is always relative to the base imported file
108
+ * @default false
109
+ */
110
+ rewriteUrls?: boolean | 'all' | 'local' | 'off';
111
+ /**
112
+ * How to process math operations
113
+ * - 'always': eagerly try to solve all operations
114
+ * - 'parens-division': require parens for division "/"
115
+ * - 'parens' or 'strict': require parens for all operations
116
+ * @default 'parens-division'
117
+ */
118
+ mathMode?: MathMode;
119
+ /**
120
+ * How to handle unit conversions in math operations
121
+ * - 'loose': Less's default 1.x-4.x behavior
122
+ * - 'preserve': Create calc() expressions for unit errors
123
+ * - 'strict': strict unit mode
124
+ * @default 'preserve'
125
+ */
126
+ unitMode?: UnitMode;
127
+ /**
128
+ * How to handle equality/coercion in guards and comparisons.
129
+ * - 'coerce': Less-compatible coercion behavior
130
+ * - 'strict': type-strict behavior
131
+ * @default 'coerce'
132
+ */
133
+ equalityMode?: EqualityMode;
134
+ /**
135
+ * @deprecated Use `mathMode` instead. This option maps to `mathMode` as follows:
136
+ * - 0 or 'always' → 'always'
137
+ * - 1 or 'parens-division' → 'parens-division'
138
+ * - 2 or 'parens' or 'strict' → 'parens'
139
+ * - 3 or 'strict-legacy' → 'parens' (removed, will default to 'strict)
140
+ * @default undefined (uses mathMode if provided, otherwise 'parens-division')
141
+ */
142
+ math?: 0 | 1 | 2 | 3 | MathMode | 'strict-legacy';
143
+ /**
144
+ * @deprecated Use `unitMode` instead. If `true`, sets `unitMode` to 'strict'.
145
+ * If `false`, sets the unitMode to 'loose.
146
+ * If undefined, uses the `unitMode` value (defaults to 'preserve').
147
+ * @default false
148
+ */
149
+ strictUnits?: boolean;
150
+ /**
151
+ * Effectively the declaration is put at the top of your base Less file,
152
+ * meaning it can be used but it also can be overridden if this variable
153
+ * is defined in the file.
154
+ * @default null
155
+ */
156
+ globalVars?: Record<string, string> | null;
157
+ /**
158
+ * As opposed to the global variable option, this puts the declaration at the
159
+ * end of your base file, meaning it will override anything defined in your Less file.
160
+ * @default null
161
+ */
162
+ modifyVars?: Record<string, string> | null;
163
+ /**
164
+ * This option allows you to specify a argument to go on to every URL.
165
+ * @default ''
166
+ */
167
+ urlArgs?: string;
168
+ /**
169
+ * @removed The dumpLineNumbers option is not useful nor supported in browsers. Use sourcemaps instead.
170
+ *
171
+ * @default undefined
172
+ */
173
+ dumpLineNumbers?: string;
174
+ /**
175
+ * Source map options
176
+ * @default undefined
177
+ */
178
+ sourceMap?: boolean | {
179
+ sourceMapFullFilename?: string;
180
+ sourceMapRootpath?: string;
181
+ sourceMapBasepath?: string;
182
+ sourceMapURL?: string;
183
+ sourceMapFileInline?: boolean;
184
+ outputSourceFiles?: boolean;
185
+ disableSourcemapAnnotation?: boolean;
186
+ sourceMapOutputFilename?: string;
187
+ sourceMapFilename?: string;
188
+ };
189
+ /**
190
+ * Verbose output
191
+ * @default false
192
+ */
193
+ verbose?: boolean;
194
+ /**
195
+ * Silent mode (suppress errors)
196
+ * @default false
197
+ */
198
+ silent?: boolean;
199
+ /**
200
+ * Quiet mode (suppress warnings)
201
+ * @default false
202
+ */
203
+ quiet?: boolean;
204
+ /**
205
+ * @deprecated This is legacy Less behavior.
206
+ *
207
+ * Controls whether mixins and detached rulesets "leak" their inner rules.
208
+ * When true:
209
+ * - Mixins: Mixin and VarDeclaration nodes are 'public' and 'optional' respectively
210
+ * - Detached rulesets: Mixin and VarDeclaration nodes are 'public' and 'private' respectively
211
+ * When false:
212
+ * - Both mixins and detached rulesets: Mixin and VarDeclaration nodes are 'private'
213
+ * @default true
214
+ */
215
+ leakyRules?: boolean;
216
+ /**
217
+ * Whether to collapse nested selectors (Less 1.x-4.x style flattening)
218
+ * When true, nested selectors like `.parent { .child { } }` are flattened to `.parent .child { }`
219
+ * @default false
220
+ */
221
+ collapseNesting?: boolean;
222
+ /**
223
+ * @deprecated This is legacy Less behavior.
224
+ *
225
+ * Whether to bubble root-only at-rules (@font-face, @keyframes, etc.) to the root
226
+ * when they are nested inside rulesets. Modern CSS supports nesting these at-rules.
227
+ * @default true
228
+ */
229
+ bubbleRootAtRules?: boolean;
230
+ }
231
+ /**
232
+ * Base interface for file-matching options
233
+ */
234
+ export interface FileMatchOptions {
235
+ /**
236
+ * File path, relative path, or glob pattern for matching.
237
+ * If omitted, the options serve as defaults.
238
+ */
239
+ file?: string;
240
+ }
241
+ /**
242
+ * Input file options - can override compile and language settings per input file
243
+ */
244
+ export interface InputOptions extends FileMatchOptions {
245
+ mathMode?: MathMode;
246
+ unitMode?: UnitMode;
247
+ equalityMode?: EqualityMode;
248
+ searchPaths?: string[];
249
+ enableJavaScript?: boolean;
250
+ javascriptEnabled?: boolean;
251
+ paths?: string[];
252
+ globalVars?: Record<string, string> | null;
253
+ modifyVars?: Record<string, string> | null;
254
+ strictImports?: boolean | 'error';
255
+ rewriteUrls?: boolean | 'all' | 'local' | 'off';
256
+ rootpath?: string;
257
+ leakyRules?: boolean;
258
+ collapseNesting?: boolean;
259
+ bubbleRootAtRules?: boolean;
260
+ /** Allow additional language-specific options */
261
+ [key: string]: any;
262
+ }
263
+ /**
264
+ * Output file options - can override output settings per output file
265
+ */
266
+ export interface OutputOptions extends FileMatchOptions {
267
+ collapseNesting?: boolean;
268
+ compress?: boolean;
269
+ sourceMap?: boolean | {
270
+ sourceMapFullFilename?: string;
271
+ sourceMapRootpath?: string;
272
+ sourceMapBasepath?: string;
273
+ sourceMapURL?: string;
274
+ sourceMapFileInline?: boolean;
275
+ outputSourceFiles?: boolean;
276
+ disableSourcemapAnnotation?: boolean;
277
+ sourceMapOutputFilename?: string;
278
+ sourceMapFilename?: string;
279
+ };
280
+ /** Allow additional options */
281
+ [key: string]: any;
282
+ }
283
+ export interface StylesConfig {
284
+ compile?: {
285
+ /**
286
+ * Plugins can be specified as:
287
+ * - Plugin instances (PluginInterface from @jesscss/core)
288
+ * - String keys (plugin names that get resolved elsewhere)
289
+ *
290
+ * @note - Using `any` here to avoid circular dependency with @jesscss/core.
291
+ * The actual type is PluginInterface from @jesscss/core.
292
+ */
293
+ plugins?: Array<any | string>;
294
+ searchPaths?: string[];
295
+ enableJavaScript?: boolean;
296
+ javascript?: CompileJavaScriptOption;
297
+ mathMode?: MathMode;
298
+ unitMode?: UnitMode;
299
+ equalityMode?: EqualityMode;
300
+ };
301
+ /**
302
+ * Input file options. Can be a single object for defaults, or an array
303
+ * where entries can have a `file` property (path or glob) to match specific inputs.
304
+ * Entries without a `file` property serve as defaults.
305
+ */
306
+ input?: InputOptions | InputOptions[];
307
+ /**
308
+ * Output file options. Can be a single object for defaults, or an array
309
+ * where entries can have a `file` property (path or glob) to match specific outputs.
310
+ * Entries without a `file` property serve as defaults.
311
+ */
312
+ output?: OutputOptions | OutputOptions[];
313
+ language?: {
314
+ less?: LessOptions;
315
+ scss?: Record<string, any>;
316
+ css?: Record<string, any>;
317
+ jess?: Record<string, any>;
318
+ [key: string]: LessOptions | Record<string, any> | undefined;
319
+ };
320
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,EAAE;QACR;;;;;;;WAOG;QACH,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC;QAC9B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;QACvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAC3B,QAAQ,CAAC,EAAE,QAAQ,CAAC;QACpB,QAAQ,CAAC,EAAE,QAAQ,CAAC;KACrB,CAAC;IACF,MAAM,CAAC,EAAE;QACP,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,SAAS,CAAC,EAAE,OAAO,CAAC;KACrB,CAAC;IACF,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,WAAW,CAAC;QACnB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC3B,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC1B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC3B,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CAAC;KAC9D,CAAC;CACH;AAGD,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACrE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC"}
package/lib/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "styles-config",
3
+ "publishConfig": {
4
+ "access": "public"
5
+ },
6
+ "version": "2.0.0-alpha.1",
7
+ "description": "General-purpose configuration for styling frameworks (Jess, Less, Sass, Tailwind, etc.)",
8
+ "main": "lib/index.js",
9
+ "types": "lib/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "import": "./lib/index.js",
13
+ "types": "./lib/index.d.ts",
14
+ "source": "./src/index.ts"
15
+ }
16
+ },
17
+ "dependencies": {
18
+ "cosmiconfig": "^9.0.0",
19
+ "picomatch": "^4.0.2",
20
+ "@jesscss/core": "2.0.0-alpha.1"
21
+ },
22
+ "devDependencies": {
23
+ "@types/node": "^22.10.2",
24
+ "@types/picomatch": "^3.0.1",
25
+ "typescript": "^5.7.2",
26
+ "vitest": "^2.1.8"
27
+ },
28
+ "author": "Matthew Dean",
29
+ "license": "MIT",
30
+ "scripts": {
31
+ "build": "pnpm compile",
32
+ "compile": "tsc -p tsconfig.build.json",
33
+ "test": "vitest"
34
+ }
35
+ }
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './types.js';
2
+ export * from './loader.js';
3
+ export * from './options.js';
package/src/loader.ts ADDED
@@ -0,0 +1,112 @@
1
+ import { cosmiconfig, cosmiconfigSync, defaultLoadersSync } from 'cosmiconfig';
2
+ import type { StylesConfig } from './types.js';
3
+
4
+ export interface LoadedConfigMeta {
5
+ config: StylesConfig;
6
+ configFilePath?: string;
7
+ }
8
+
9
+ const explorer = cosmiconfig('styles', {
10
+ searchPlaces: [
11
+ 'styles.config.ts',
12
+ 'styles.config.js',
13
+ 'styles.config.mts',
14
+ 'styles.config.mjs',
15
+ 'styles.config.cjs',
16
+ 'styles.config.cts'
17
+ ],
18
+ loaders: {
19
+ // eslint-disable-next-line @typescript-eslint/naming-convention
20
+ '.mts': defaultLoadersSync['.ts'],
21
+ // eslint-disable-next-line @typescript-eslint/naming-convention
22
+ '.cts': defaultLoadersSync['.ts'],
23
+ // eslint-disable-next-line @typescript-eslint/naming-convention
24
+ '.mjs': defaultLoadersSync['.js'],
25
+ // eslint-disable-next-line @typescript-eslint/naming-convention
26
+ '.cjs': defaultLoadersSync['.cjs']
27
+ }
28
+ });
29
+
30
+ const explorerSync = cosmiconfigSync('styles', {
31
+ searchPlaces: [
32
+ 'styles.config.ts',
33
+ 'styles.config.js',
34
+ 'styles.config.mts',
35
+ 'styles.config.mjs',
36
+ 'styles.config.cjs',
37
+ 'styles.config.cts'
38
+ ],
39
+ loaders: {
40
+ // eslint-disable-next-line @typescript-eslint/naming-convention
41
+ '.mts': defaultLoadersSync['.ts'],
42
+ // eslint-disable-next-line @typescript-eslint/naming-convention
43
+ '.cts': defaultLoadersSync['.ts'],
44
+ // eslint-disable-next-line @typescript-eslint/naming-convention
45
+ '.mjs': defaultLoadersSync['.js'],
46
+ // eslint-disable-next-line @typescript-eslint/naming-convention
47
+ '.cjs': defaultLoadersSync['.cjs']
48
+ }
49
+ });
50
+
51
+ /**
52
+ * Load styles configuration from the file system (async)
53
+ * @param searchFrom - Directory to search from (defaults to process.cwd())
54
+ * @returns Configuration object or null if not found
55
+ */
56
+ export async function loadConfig(searchFrom?: string): Promise<StylesConfig | null> {
57
+ const result = await explorer.search(searchFrom);
58
+ return result?.config ? normalizeConfig(result.config) : null;
59
+ }
60
+
61
+ /**
62
+ * Load styles configuration from the file system (sync)
63
+ * @param searchFrom - Directory to search from (defaults to process.cwd())
64
+ * @returns Configuration object or empty object if not found
65
+ */
66
+ export function loadConfigSync(searchFrom?: string): StylesConfig {
67
+ const result = explorerSync.search(searchFrom);
68
+ return result?.config ? normalizeConfig(result.config) : {};
69
+ }
70
+
71
+ /**
72
+ * Load styles configuration with metadata (sync).
73
+ * Includes config file path when a config file is discovered.
74
+ */
75
+ export function loadConfigSyncWithMeta(searchFrom?: string): LoadedConfigMeta {
76
+ const result = explorerSync.search(searchFrom);
77
+ return {
78
+ config: result?.config ? normalizeConfig(result.config) : {},
79
+ configFilePath: result?.filepath
80
+ };
81
+ }
82
+
83
+ /**
84
+ * Load styles configuration from a specific file path (async)
85
+ * @param filePath - Path to the config file
86
+ * @returns Configuration object or null if not found
87
+ */
88
+ export async function loadConfigFromPath(filePath: string): Promise<StylesConfig | null> {
89
+ const result = await explorer.load(filePath);
90
+ return result?.config ? normalizeConfig(result.config) : null;
91
+ }
92
+
93
+ /**
94
+ * Load styles configuration from a specific file path (sync)
95
+ * @param filePath - Path to the config file
96
+ * @returns Configuration object or empty object if not found
97
+ */
98
+ export function loadConfigFromPathSync(filePath: string): StylesConfig {
99
+ const result = explorerSync.load(filePath);
100
+ return result?.config ? normalizeConfig(result.config) : {};
101
+ }
102
+
103
+ /**
104
+ * Normalize config object - handle default exports and ensure proper type
105
+ */
106
+ function normalizeConfig(config: any): StylesConfig {
107
+ // Handle default export (common in ES modules)
108
+ if (typeof config === 'object' && config !== null && 'default' in config) {
109
+ return config.default as StylesConfig;
110
+ }
111
+ return config as StylesConfig;
112
+ }