@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 +21 -0
- package/README.md +112 -0
- package/dist/configs/eslint.config.mjs +256 -0
- package/dist/configs/stylelint.config.mjs +78 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +75 -0
- package/dist/rules/async-suffix.js +121 -0
- package/dist/rules/class-name-match-filename.js +34 -0
- package/dist/rules/default-props-are-static-readonly.js +48 -0
- package/dist/rules/events-are-in-camel-case.js +140 -0
- package/dist/rules/force-dynamic-vue-imports-in-router.js +80 -0
- package/dist/rules/force-dynamic-vue-imports-in-services.js +160 -0
- package/dist/rules/get-set-adjacent.js +154 -0
- package/dist/rules/get-set-one-liner.js +156 -0
- package/dist/rules/no-api-in-entity.js +32 -0
- package/dist/rules/no-api-in-setup.js +31 -0
- package/dist/rules/no-entity-in-service.js +31 -0
- package/dist/rules/no-export-type-in-ts.js +36 -0
- package/dist/rules/popables-are-readonly.js +52 -0
- package/dist/rules/private-property-if-only-in-template.js +192 -0
- package/dist/rules/state-are-private-readonly.js +89 -0
- package/dist/rules/template-refs-are-readonly.js +52 -0
- package/dist/types.d.ts +10 -0
- package/dist/types.js +17 -0
- package/dist/utils.d.ts +29 -0
- package/dist/utils.js +66 -0
- package/package.json +66 -0
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
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -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
|
+
};
|