@orion.ui/orion-linter 1.0.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Orion UI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,112 @@
1
+ # @orion.ui/orion-linter
2
+
3
+ Shared linting configurations and custom rules for Orion UI projects. This package provides a unified code style guide using ESLint (with custom TypeScript and Vue rules) and Stylelint.
4
+
5
+ ## Features
6
+
7
+ - **ESLint**:
8
+ - TypeScript support
9
+ - Vue.js 3 support
10
+ - Stylistic rules
11
+ - Custom rules for Orion architecture patterns
12
+ - **Stylelint**:
13
+ - LESS support
14
+ - BEM naming convention
15
+ - Property ordering (clean order)
16
+ - Unit filtering
17
+
18
+ ## Installation
19
+
20
+ Install the package and its peer dependencies:
21
+
22
+ ```bash
23
+ npm install -D @orion.ui/orion-linter eslint stylelint typescript
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ ### ESLint Configuration
29
+
30
+ Create an `eslint.config.mjs` file in your project root:
31
+
32
+ ```javascript
33
+ import { getESLintConfig } from '@orion.ui/orion-linter';
34
+ export default await getESLintConfig();
35
+ ```
36
+
37
+ OR
38
+
39
+ ```javascript
40
+ import { getESLintConfig } from '@orion.ui/orion-linter';
41
+
42
+ const orionConfig = await getESLintConfig();
43
+
44
+ export default [
45
+ ...orionConfig,
46
+ {
47
+ // Your custom overrides here
48
+ rules: {
49
+ // ...
50
+ }
51
+ }
52
+ ];
53
+ ```
54
+
55
+ ### Stylelint Configuration
56
+
57
+ Create a `stylelint.config.mjs` file in your project root:
58
+
59
+ ```javascript
60
+ import { getStylelintConfig } from '@orion.ui/orion-linter';
61
+ export default await getStylelintConfig();
62
+ ```
63
+
64
+ OR
65
+
66
+ ```javascript
67
+ import { getStylelintConfig } from '@orion.ui/orion-linter';
68
+
69
+ const orionConfig = await getStylelintConfig();
70
+
71
+ export default {
72
+ ...orionConfig,
73
+ rules: {
74
+ ...orionConfig.rules,
75
+ // Your custom overrides here
76
+ }
77
+ };
78
+ ```
79
+
80
+ ## Custom ESLint Rules
81
+
82
+ This package includes several custom rules designed to enforce architectural patterns within Orion projects. All rules are prefixed with `orion-rules/`.
83
+
84
+ | Rule Name | Description |
85
+ |-----------|-------------|
86
+ | `async-suffix` | Enforces async functions to have an 'Async' suffix. |
87
+ | `class-name-match-filename` | Ensures class names match their filenames. |
88
+ | `default-props-are-static-readonly` | Enforces default props to be static readonly. |
89
+ | `events-are-in-camel-case` | Enforces event names to be in camelCase. |
90
+ | `force-dynamic-vue-imports-in-router` | Requires dynamic imports for Vue components in router files. |
91
+ | `force-dynamic-vue-imports-in-services` | Requires dynamic imports for Vue components in services. |
92
+ | `get-set-adjacent` | Enforces getters and setters to be defined adjacently. |
93
+ | `get-set-one-liner` | Enforces simple getters and setters to be on a single line. |
94
+ | `no-api-in-entity` | Prevents API usage inside Entity classes. |
95
+ | `no-api-in-setup` | Prevents API usage inside Vue setup functions (use services instead). |
96
+ | `no-entity-in-service` | Prevents Entity usage inside Service classes. |
97
+ | `no-export-type-in-ts` | Disallows exporting types in `.ts` files (prefer `.d.ts` files). |
98
+ | `popables-are-readonly` | Enforces "popable" properties to be readonly. |
99
+ | `private-property-if-only-in-template` | Ensures properties not used in the template are marked as private. |
100
+ | `state-are-private-readonly` | Enforces state properties to be private and readonly. |
101
+ | `template-refs-are-readonly` | Enforces template refs to be readonly. |
102
+
103
+ ## Requirements
104
+
105
+ - Node.js >= 18.12.0
106
+ - ESLint >= 9.0.0
107
+ - Stylelint >= 16.0.0
108
+ - TypeScript >= 5.0.0
109
+
110
+ ## License
111
+
112
+ MIT
@@ -0,0 +1,256 @@
1
+ import eslintStylistic from '@stylistic/eslint-plugin';
2
+ import tsEslintPlugin from '@typescript-eslint/eslint-plugin';
3
+ import tsParser from '@typescript-eslint/parser';
4
+ import eslintVue from 'eslint-plugin-vue';
5
+ import asyncSuffix from '../rules/async-suffix.js';
6
+ import classNameMatchFilename from '../rules/class-name-match-filename.js';
7
+ import defaultPropsAreStaticReadonly from '../rules/default-props-are-static-readonly.js';
8
+ import eventAreInCamelCase from '../rules/events-are-in-camel-case.js';
9
+ import forceDynamicVueImportsInRouter from '../rules/force-dynamic-vue-imports-in-router.js';
10
+ import forceDynamicVueImportsInServices from '../rules/force-dynamic-vue-imports-in-services.js';
11
+ import getSetAdjacent from '../rules/get-set-adjacent.js';
12
+ import getSetOneLiner from '../rules/get-set-one-liner.js';
13
+ import noApiInEntity from '../rules/no-api-in-entity.js';
14
+ import noApiInSetup from '../rules/no-api-in-setup.js';
15
+ import noEntityInService from '../rules/no-entity-in-service.js';
16
+ import noExportTypeInTs from '../rules/no-export-type-in-ts.js';
17
+ import popablesAreReadonly from '../rules/popables-are-readonly.js';
18
+ import privatePropertyIfOnlyInTemplate from '../rules/private-property-if-only-in-template.js';
19
+ import stateArePrivateReadonly from '../rules/state-are-private-readonly.js';
20
+ import templateRefsAreReadonly from '../rules/template-refs-are-readonly.js';
21
+
22
+ // Common configuration for Orion plugins
23
+ const orionRulesPlugin = {
24
+ 'orion-rules': {
25
+ rules: {
26
+ 'async-suffix': asyncSuffix,
27
+ 'no-api-in-entity': noApiInEntity,
28
+ 'no-api-in-setup': noApiInSetup,
29
+ 'no-entity-in-service': noEntityInService,
30
+ 'no-export-type-in-ts': noExportTypeInTs,
31
+ 'template-refs-are-readonly': templateRefsAreReadonly,
32
+ 'default-props-are-static-readonly': defaultPropsAreStaticReadonly,
33
+ 'state-are-private-readonly': stateArePrivateReadonly,
34
+ 'class-name-match-filename': classNameMatchFilename,
35
+ 'popables-are-readonly': popablesAreReadonly,
36
+ 'force-dynamic-vue-imports-in-services': forceDynamicVueImportsInServices,
37
+ 'force-dynamic-vue-imports-in-router': forceDynamicVueImportsInRouter,
38
+ 'get-set-one-liner': getSetOneLiner,
39
+ 'get-set-adjacent': getSetAdjacent,
40
+ 'events-are-in-camel-case': eventAreInCamelCase,
41
+ 'private-property-if-only-in-template': privatePropertyIfOnlyInTemplate
42
+ },
43
+ },
44
+ };
45
+
46
+ const plugins = { ...orionRulesPlugin, '@typescript-eslint': tsEslintPlugin };
47
+
48
+ export default [
49
+ eslintStylistic.configs['recommended'],
50
+ ...eslintVue.configs['flat/recommended'],
51
+
52
+ { ignores: ['src/typings/**/*.ts', 'src/assets'] },
53
+
54
+ // —————————————————————————————————————————————————————————————————————————————
55
+ // TS & JS files
56
+ // —————————————————————————————————————————————————————————————————————————————
57
+ {
58
+ files: ['**/*.ts', '**/*.tsx'],
59
+ languageOptions: {
60
+ parser: tsParser,
61
+ parserOptions: { jsx: true },
62
+ },
63
+ plugins,
64
+ },
65
+ {
66
+ files: ['**/*.js', '**/*.jsx'],
67
+ languageOptions: { parserOptions: { jsx: true } },
68
+ plugins,
69
+ },
70
+ {
71
+ rules: {
72
+ 'no-unused-vars': [ // Generic JS rule (disabled for TS below)
73
+ 'warn', {
74
+ vars: 'all',
75
+ args: 'after-used',
76
+ caughtErrors: 'none',
77
+ argsIgnorePattern: '^(props|emits|_aside|_modal)$',
78
+ },
79
+ ],
80
+ 'eqeqeq': ['error', 'smart'],
81
+ 'no-console': 'warn',
82
+ 'no-debugger': 'error',
83
+ 'no-restricted-exports': ['error', { 'restrictDefaultExports': { "direct": true } }],
84
+ '@stylistic/space-before-function-paren': ['error', 'always'],
85
+ '@stylistic/array-bracket-newline': ['error', { multiline: true }],
86
+ '@stylistic/no-tabs': 'off',
87
+ '@stylistic/quote-props': ['error', 'as-needed', { unnecessary: false }],
88
+ '@stylistic/indent': ['error', 'tab'],
89
+ '@stylistic/semi': ['error', 'always', { omitLastInOneLineBlock: true }],
90
+ '@stylistic/padded-blocks': ['error', { classes: 'always' }],
91
+ '@stylistic/object-curly-newline': [
92
+ 'error', {
93
+ ObjectExpression: { multiline: true },
94
+ ObjectPattern: { multiline: true },
95
+ ImportDeclaration: 'never',
96
+ ExportDeclaration: { multiline: true },
97
+ },
98
+ ],
99
+
100
+ // Custom local rules
101
+ 'orion-rules/no-api-in-entity': 'error',
102
+ 'orion-rules/no-api-in-setup': 'error',
103
+ 'orion-rules/no-entity-in-service': 'error',
104
+ 'orion-rules/no-export-type-in-ts': 'error',
105
+ 'orion-rules/template-refs-are-readonly': 'error',
106
+ 'orion-rules/default-props-are-static-readonly': 'error',
107
+ 'orion-rules/state-are-private-readonly': 'error',
108
+ 'orion-rules/class-name-match-filename': 'error',
109
+ 'orion-rules/popables-are-readonly': 'error',
110
+ 'orion-rules/async-suffix': 'error',
111
+ 'orion-rules/get-set-one-liner': 'error',
112
+ 'orion-rules/get-set-adjacent': 'error',
113
+ 'orion-rules/events-are-in-camel-case': 'error',
114
+ },
115
+ },
116
+
117
+ // —————————————————————————————————————————————————————————————————————————————
118
+ // Rules specific to TS files
119
+ // Specific TS override to replace core rule with one from typescript-eslint
120
+ // —————————————————————————————————————————————————————————————————————————————
121
+ {
122
+ files: ['**/*.ts', '**/*.tsx'],
123
+ rules: {
124
+ 'no-unused-vars': 'off',
125
+ '@stylistic/no-mixed-spaces-and-tabs':[ 'warn', 'smart-tabs'],
126
+ '@typescript-eslint/no-unused-vars': [
127
+ 'warn', {
128
+ vars: 'all',
129
+ args: 'after-used',
130
+ caughtErrors: 'none',
131
+ ignoreRestSiblings: true,
132
+ // Important: named parameters in type signatures (function types, constructors, etc.)
133
+ // will not be considered runtime variables by the TS version of the rule,
134
+ // thus removing the cited false positives (ex: (...args: any[]) in a type / callback / constructor signature).
135
+ },
136
+ ],
137
+ },
138
+ },
139
+
140
+ // —————————————————————————————————————————————————————————————————————————————
141
+ // Rules specific to router files
142
+ // —————————————————————————————————————————————————————————————————————————————
143
+ {
144
+ files: ['**/router/*.ts'],
145
+ plugins,
146
+ rules: {
147
+ 'orion-rules/force-dynamic-vue-imports-in-router': 'error',
148
+ },
149
+ },
150
+
151
+ // —————————————————————————————————————————————————————————————————————————————
152
+ // Rules specific to *Service.ts and *Setup.ts files
153
+ // —————————————————————————————————————————————————————————————————————————————
154
+ {
155
+ files: ['**/*Service.ts', '**/*Setup.ts'],
156
+ plugins,
157
+ rules: {
158
+ 'orion-rules/force-dynamic-vue-imports-in-services': 'error',
159
+ },
160
+ },
161
+
162
+ // —————————————————————————————————————————————————————————————————————————————
163
+ // Rules specific to d.ts files
164
+ // —————————————————————————————————————————————————————————————————————————————
165
+ {
166
+ files: ['**/*.d.ts'],
167
+ rules: {
168
+ 'no-unused-vars': 'off',
169
+ },
170
+ },
171
+
172
+ // —————————————————————————————————————————————————————————————————————————————
173
+ // Rules specific to Vue files
174
+ // —————————————————————————————————————————————————————————————————————————————
175
+ {
176
+ files: ['**/*.vue'],
177
+ languageOptions: { parserOptions: { parser: tsParser } },
178
+ plugins,
179
+ rules: {
180
+ 'no-unused-vars': [
181
+ 'warn', {
182
+ vars: 'all',
183
+ args: 'after-used',
184
+ caughtErrors: 'all',
185
+ varsIgnorePattern: '^setup$',
186
+ },
187
+ ],
188
+ 'vue/comma-dangle': ['error', 'always-multiline'],
189
+ 'vue/comma-spacing': ['error', { before: false, after: true }],
190
+ 'vue/object-curly-spacing': ['error', 'always'],
191
+ 'vue/component-name-in-template-casing': ['error', 'kebab-case'],
192
+ 'vue/no-v-html': 'off',
193
+ 'vue/html-indent': [
194
+ 'error',
195
+ 'tab',
196
+ {
197
+ attribute: 1,
198
+ baseIndent: 1,
199
+ closeBracket: 0,
200
+ alignAttributesVertically: true,
201
+ ignores: [],
202
+ },
203
+ ],
204
+ 'vue/first-attribute-linebreak': [
205
+ 'error', {
206
+ singleline: 'beside',
207
+ multiline: 'below',
208
+ },
209
+ ],
210
+ 'vue/html-closing-bracket-newline': [
211
+ 'error',
212
+ {
213
+ singleline: 'never',
214
+ multiline: 'never',
215
+ },
216
+ ],
217
+ 'vue/html-closing-bracket-spacing': [
218
+ 'error',
219
+ {
220
+ startTag: 'never',
221
+ endTag: 'never',
222
+ selfClosingTag: 'never',
223
+ },
224
+ ],
225
+ 'vue/singleline-html-element-content-newline': [
226
+ 'error',
227
+ {
228
+ ignoreWhenNoAttributes: true,
229
+ ignoreWhenEmpty: true,
230
+ ignores: ['pre', 'textarea', 'div'],
231
+ },
232
+ ],
233
+ 'vue/space-infix-ops': process.env.NODE_ENV !== 'development'
234
+ ? 'off'
235
+ : ['error', { int32Hint: false }],
236
+ },
237
+ },
238
+
239
+ // —————————————————————————————————————————————————————————————————————————————
240
+ // Rules specific to *SetupService.ts and *Setup.ts files
241
+ // —————————————————————————————————————————————————————————————————————————————
242
+ {
243
+ files: ['**/*SetupService.ts', '**/*Setup.ts'],
244
+ rules: {
245
+ 'orion-rules/private-property-if-only-in-template': 'error',
246
+ },
247
+ },
248
+
249
+ // —————————————————————————————————————————————————————————————————————————————
250
+ // Rules specific for *.config.(ts|js|mjs) files
251
+ // —————————————————————————————————————————————————————————————————————————————
252
+ {
253
+ files: ['**/*.config.ts', '**/*.config.js', 'eslint.config.mjs'],
254
+ rules: { 'no-restricted-exports': 'off' },
255
+ },
256
+ ];
@@ -0,0 +1,78 @@
1
+ import { propertyGroups } from 'stylelint-config-clean-order';
2
+
3
+ const propertiesOrder = propertyGroups.map(properties => ({
4
+ noEmptyLineBetween: true,
5
+ emptyLineBefore: 'never', // Don't add empty lines between order groups.
6
+ properties,
7
+ }));
8
+
9
+ /** @type {import('stylelint').Config} */
10
+ export default {
11
+ ignoreFiles: [
12
+ 'src/assets/**/*',
13
+ 'src/**/*.ts',
14
+ 'src/Dockerfile',
15
+ ],
16
+
17
+ extends: [
18
+ 'stylelint-config-standard-less',
19
+ 'stylelint-config-recommended-vue',
20
+ '@stylistic/stylelint-config',
21
+ 'stylelint-config-clean-order',
22
+ ],
23
+
24
+ rules: {
25
+ '@stylistic/max-line-length': null,
26
+ '@stylistic/indentation': 'tab',
27
+
28
+ 'less/no-duplicate-variables': null,
29
+
30
+ 'media-query-no-invalid': null,
31
+ 'declaration-block-no-duplicate-properties': [true, { ignore: ['consecutive-duplicates'] }],
32
+ 'unit-allowed-list': ['px', 'rem', 'em', 'fr', '%', 's', 'deg', 'dvh', 'vh', 'dvw', 'vw'],
33
+ 'declaration-property-unit-allowed-list': {
34
+ '/^font-size$/': ['rem', 'em'],
35
+ '/^(((row|column)-)?gap|(padding|margin)(-[a-z]+)?)$/': ['rem'],
36
+ '/^(max-)?(width|height)$/': ['rem', 'dvh', 'vh', 'dvw', 'vw', '%'],
37
+ '/^flex(-basis)?$/': ['%', 'rem'],
38
+ },
39
+ "declaration-block-no-redundant-longhand-properties": [true, { "ignoreShorthands": ["grid-template"] }],
40
+ 'order/properties-order': [
41
+ propertiesOrder,
42
+ {
43
+ severity: 'warning',
44
+ unspecified: 'bottomAlphabetical',
45
+ },
46
+ ],
47
+
48
+ 'selector-class-pattern': [ // BEM naming convention
49
+ '^[a-z]([-]?[a-z0-9]+)*(__[a-z0-9]([-]?[a-z0-9]+)*)?(--[a-z0-9]([-]?[a-z0-9]+)*)?$',
50
+ {
51
+ /**
52
+ * Resolve nested selectors with & interpolation.
53
+ * https://stylelint.io/user-guide/rules/selector-class-pattern/#resolvenestedselectors-true--false-default-false
54
+ * */
55
+ resolveNestedSelectors: true,
56
+ message: function expected (selectorValue) {
57
+ return `Expected class selector "${selectorValue}" to match BEM CSS pattern https://en.bem.info/methodology/css. Selector validation tool: https://regexr.com/3apms`;
58
+ },
59
+ },
60
+ ],
61
+ },
62
+
63
+ overrides: [
64
+ {
65
+ files: ['**/*.vue'],
66
+ customSyntax: 'postcss-html',
67
+ rules: {
68
+ 'block-no-empty': null,
69
+ 'no-empty-source': null, // Allow empty sources in Vue files
70
+ },
71
+ },
72
+ {
73
+ files: ['**/*.less'],
74
+ customSyntax: 'postcss-less',
75
+ rules: { '@stylistic/indentation': 'tab' },
76
+ },
77
+ ],
78
+ };
@@ -0,0 +1,45 @@
1
+ export * from './types.js';
2
+ export * from './utils.js';
3
+ /**
4
+ * Get the path to the ESLint configuration file
5
+ * @returns Absolute path to eslint.config.mjs (ESM module)
6
+ */
7
+ export declare function getESLintConfigPath(): string;
8
+ /**
9
+ * Get the path to the Stylelint configuration file
10
+ * @returns Absolute path to stylelint.config.mjs (ESM module)
11
+ */
12
+ export declare function getStylelintConfigPath(): string;
13
+ /**
14
+ * Import and return the ESLint configuration object
15
+ * @returns ESLint configuration object
16
+ */
17
+ export declare function getESLintConfig(): Promise<any>;
18
+ /**
19
+ * Import and return the Stylelint configuration object
20
+ * @returns Stylelint configuration object
21
+ */
22
+ export declare function getStylelintConfig(): Promise<any>;
23
+ export declare const paths: {
24
+ eslintConfig: string;
25
+ stylelintConfig: string;
26
+ };
27
+ export declare const configs: {
28
+ getESLintConfig: typeof getESLintConfig;
29
+ getStylelintConfig: typeof getStylelintConfig;
30
+ };
31
+ declare const _default: {
32
+ paths: {
33
+ eslintConfig: string;
34
+ stylelintConfig: string;
35
+ };
36
+ configs: {
37
+ getESLintConfig: typeof getESLintConfig;
38
+ getStylelintConfig: typeof getStylelintConfig;
39
+ };
40
+ getESLintConfigPath: typeof getESLintConfigPath;
41
+ getStylelintConfigPath: typeof getStylelintConfigPath;
42
+ getESLintConfig: typeof getESLintConfig;
43
+ getStylelintConfig: typeof getStylelintConfig;
44
+ };
45
+ export default _default;
package/dist/index.js ADDED
@@ -0,0 +1,75 @@
1
+ import { dirname, resolve } from 'node:path';
2
+ import { fileURLToPath, pathToFileURL } from 'node:url';
3
+ // ESM equivalent of __dirname
4
+ const __filename = fileURLToPath(import.meta.url);
5
+ const __dirname = dirname(__filename);
6
+ // Export types and utilities
7
+ export * from './types.js';
8
+ export * from './utils.js';
9
+ /**
10
+ * Get the path to the ESLint configuration file
11
+ * @returns Absolute path to eslint.config.mjs (ESM module)
12
+ */
13
+ export function getESLintConfigPath() {
14
+ return resolve(__dirname, './configs/eslint.config.mjs');
15
+ }
16
+ /**
17
+ * Get the path to the Stylelint configuration file
18
+ * @returns Absolute path to stylelint.config.mjs (ESM module)
19
+ */
20
+ export function getStylelintConfigPath() {
21
+ return resolve(__dirname, './configs/stylelint.config.mjs');
22
+ }
23
+ /**
24
+ * Import and return the ESLint configuration object
25
+ * @returns ESLint configuration object
26
+ */
27
+ export async function getESLintConfig() {
28
+ const configPath = getESLintConfigPath();
29
+ try {
30
+ // Convert Windows path to file:// URL for ESM compatibility
31
+ const configUrl = pathToFileURL(configPath).href;
32
+ // Use dynamic import for ESM modules
33
+ const config = await import(configUrl);
34
+ return config.default || config;
35
+ }
36
+ catch (error) {
37
+ throw new Error(`Failed to load ESLint configuration from ${configPath}: ${error}`);
38
+ }
39
+ }
40
+ /**
41
+ * Import and return the Stylelint configuration object
42
+ * @returns Stylelint configuration object
43
+ */
44
+ export async function getStylelintConfig() {
45
+ const configPath = getStylelintConfigPath();
46
+ try {
47
+ // Convert Windows path to file:// URL for ESM compatibility
48
+ const configUrl = pathToFileURL(configPath).href;
49
+ // Use dynamic import for ESM modules
50
+ const config = await import(configUrl);
51
+ return config.default || config;
52
+ }
53
+ catch (error) {
54
+ throw new Error(`Failed to load Stylelint configuration from ${configPath}: ${error}`);
55
+ }
56
+ }
57
+ // Export paths for direct usage
58
+ export const paths = {
59
+ eslintConfig: getESLintConfigPath(),
60
+ stylelintConfig: getStylelintConfigPath(),
61
+ };
62
+ // Export configuration objects for direct usage
63
+ export const configs = {
64
+ getESLintConfig: getESLintConfig,
65
+ getStylelintConfig: getStylelintConfig,
66
+ };
67
+ // Default export for convenience
68
+ export default {
69
+ paths,
70
+ configs,
71
+ getESLintConfigPath,
72
+ getStylelintConfigPath,
73
+ getESLintConfig,
74
+ getStylelintConfig,
75
+ };