@jskit-ai/config-eslint 0.1.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/README.md ADDED
@@ -0,0 +1,329 @@
1
+ # `@jskit-ai/config-eslint`
2
+
3
+ Shared flat ESLint config presets for monorepo apps and packages.
4
+
5
+ This package gives multiple apps the same linting baseline without copy-pasting ESLint setup in each app.
6
+
7
+ ESLint is a tool that checks code quality and consistency before code reaches production. This package is a reusable "lint rules starter kit" for all workspace apps.
8
+
9
+
10
+ ## 1) What This Package Is For
11
+
12
+ Use this package when you want:
13
+
14
+ 1. Shared lint behavior across many apps.
15
+ 2. Fewer duplicated config files.
16
+ 3. Easier upgrades (change shared config once, then update package version).
17
+ 4. Predictable linting in CI across the monorepo.
18
+
19
+ Real-life example:
20
+
21
+ 1. App A and App B both use Vue + Node.
22
+ 2. Without this package, each app has its own local ESLint setup and rules drift over time.
23
+ 3. With this package, both apps import the same presets and stay aligned.
24
+
25
+ ---
26
+
27
+ ## 2) What It Exports
28
+
29
+ This package exports four flat config presets:
30
+
31
+ 1. `baseConfig`
32
+ 2. `nodeConfig`
33
+ 3. `webConfig`
34
+ 4. `vueConfig`
35
+
36
+ Important:
37
+ These are config arrays, not runtime functions. You combine them in your app `eslint.config.mjs`.
38
+
39
+ ---
40
+
41
+ ## 3) How To Install And Use It
42
+
43
+ In an app `package.json`:
44
+
45
+ ```json
46
+ {
47
+ "devDependencies": {
48
+ "@jskit-ai/config-eslint": "0.1.0"
49
+ }
50
+ }
51
+ ```
52
+
53
+ Then in `eslint.config.mjs`:
54
+
55
+ ```js
56
+ import { baseConfig, nodeConfig, webConfig, vueConfig } from "@jskit-ai/config-eslint";
57
+
58
+ export default [
59
+ ...baseConfig,
60
+ ...webConfig,
61
+ ...nodeConfig,
62
+ ...vueConfig
63
+ ];
64
+ ```
65
+
66
+ Run lint:
67
+
68
+ ```bash
69
+ npm run lint
70
+ ```
71
+
72
+ ---
73
+
74
+ ## 4) Full Export Reference (What Each Export Does + Real Examples)
75
+
76
+ ### `baseConfig`
77
+
78
+ What it does:
79
+
80
+ 1. Enables ESLint core recommended rules (`@eslint/js` recommended set).
81
+ 2. Sets modern JS parsing defaults:
82
+ 1. `ecmaVersion: "latest"`
83
+ 2. `sourceType: "module"`
84
+ 3. Applies to `**/*.{js,mjs,cjs,vue}`.
85
+
86
+ When to use it:
87
+ Always. This is the foundation preset.
88
+
89
+ Practical real-life example:
90
+
91
+ 1. Developer accidentally writes an undefined variable in a service file.
92
+ 2. `baseConfig` catches that via ESLint recommended rules before merge.
93
+
94
+ Code example:
95
+
96
+ ```js
97
+ import { baseConfig } from "@jskit-ai/config-eslint";
98
+
99
+ export default [...baseConfig];
100
+ ```
101
+
102
+ ### `nodeConfig`
103
+
104
+ What it does:
105
+
106
+ 1. Adds Node globals (for example `process`, `Buffer`, `__dirname` behavior via environment globals).
107
+ 2. Adds a `.cjs` override that sets:
108
+ 1. `sourceType: "commonjs"`
109
+ 2. Node globals for CommonJS files.
110
+
111
+ When to use it:
112
+ Use when your app/package has server code, scripts, workers, or `.cjs` files.
113
+
114
+ Practical real-life example:
115
+
116
+ 1. Your app has a `knexfile.cjs` and backend files that use Node globals.
117
+ 2. Without `nodeConfig`, lint may flag globals or module syntax incorrectly.
118
+ 3. With `nodeConfig`, those files lint with the correct runtime assumptions.
119
+
120
+ Code example:
121
+
122
+ ```js
123
+ import { baseConfig, nodeConfig } from "@jskit-ai/config-eslint";
124
+
125
+ export default [...baseConfig, ...nodeConfig];
126
+ ```
127
+
128
+ ### `webConfig`
129
+
130
+ What it does:
131
+
132
+ 1. Adds browser globals (for example `window`, `document`, `navigator`).
133
+ 2. Applies to `**/*.{js,mjs,cjs,vue}`.
134
+
135
+ When to use it:
136
+ Use when your app has browser/client code.
137
+
138
+ Practical real-life example:
139
+
140
+ 1. A frontend component uses `window.location.pathname`.
141
+ 2. Without `webConfig`, lint may treat `window` as undefined.
142
+ 3. With `webConfig`, lint understands browser globals and checks the code correctly.
143
+
144
+ Code example:
145
+
146
+ ```js
147
+ import { baseConfig, webConfig } from "@jskit-ai/config-eslint";
148
+
149
+ export default [...baseConfig, ...webConfig];
150
+ ```
151
+
152
+ ### `vueConfig`
153
+
154
+ What it does:
155
+
156
+ 1. Adds `eslint-plugin-vue` flat recommended config.
157
+ 2. Applies practical Vue rule relaxations used across apps:
158
+ 1. `vue/multi-word-component-names: off`
159
+ 2. `vue/max-attributes-per-line: off`
160
+ 3. `vue/singleline-html-element-content-newline: off`
161
+ 4. `vue/attributes-order: off`
162
+ 5. `vue/one-component-per-file: off`
163
+
164
+ When to use it:
165
+ Use when the app uses Vue single-file components.
166
+
167
+ Practical real-life example:
168
+
169
+ 1. A test file declares small inline Vue components in the same file.
170
+ 2. Without this preset override, lint can fail due to `one-component-per-file`.
171
+ 3. With `vueConfig`, the shared team convention is respected.
172
+
173
+ Code example:
174
+
175
+ ```js
176
+ import { baseConfig, webConfig, vueConfig } from "@jskit-ai/config-eslint";
177
+
178
+ export default [...baseConfig, ...webConfig, ...vueConfig];
179
+ ```
180
+
181
+ ---
182
+
183
+ ## 5) How Real Apps Use This In Practice (And Why)
184
+
185
+ In this repo, the app config at:
186
+ `apps/jskit-value-app/eslint.config.mjs`
187
+ uses:
188
+
189
+ 1. `...baseConfig`
190
+ 2. `...webConfig`
191
+ 3. `...nodeConfig`
192
+ 4. `...vueConfig`
193
+
194
+ Why this exact composition:
195
+
196
+ 1. The app is full-stack: browser + server + Vue + `.cjs`.
197
+ 2. One app has both frontend and backend folders.
198
+ 3. Shared presets reduce boilerplate while keeping app-specific rules local.
199
+
200
+ Real workflow example:
201
+
202
+ 1. Developer edits a Vue view and a Fastify service in the same PR.
203
+ 2. One lint run validates both browser and server assumptions with shared rules.
204
+ 3. CI behavior stays consistent with other apps using the same presets.
205
+
206
+ ---
207
+
208
+ ## 6) How Config Composition Works
209
+
210
+ ESLint flat config is an ordered array. Order matters.
211
+
212
+ Practical rule:
213
+
214
+ 1. Put shared presets first.
215
+ 2. Put app-specific overrides after shared presets.
216
+
217
+ Example:
218
+
219
+ ```js
220
+ import { baseConfig, nodeConfig, webConfig, vueConfig } from "@jskit-ai/config-eslint";
221
+
222
+ export default [
223
+ ...baseConfig,
224
+ ...webConfig,
225
+ ...nodeConfig,
226
+ ...vueConfig,
227
+ {
228
+ files: ["server/**/*.service.js"],
229
+ rules: {
230
+ "max-lines": [
231
+ "error",
232
+ {
233
+ max: 750,
234
+ skipBlankLines: true,
235
+ skipComments: true
236
+ }
237
+ ]
238
+ }
239
+ }
240
+ ];
241
+ ```
242
+
243
+ Why:
244
+ App-specific rules should win only where the app explicitly needs them.
245
+
246
+ ---
247
+
248
+ ## 7) What Stays In App Config (Important Boundary)
249
+
250
+ Keep these in each app, not in this shared package:
251
+
252
+ 1. App-specific ignore patterns.
253
+ 2. App-specific architecture rules.
254
+ 3. App-specific rule exceptions for local workflows.
255
+
256
+ Real-life example:
257
+
258
+ 1. One app has generated files under `coverage-client/**` and another app does not.
259
+ 2. That ignore belongs in the app, not the shared package.
260
+
261
+ This keeps `@jskit-ai/config-eslint` reusable and domain-neutral.
262
+
263
+ ---
264
+
265
+ ## 8) Common Questions
266
+
267
+ ### "Do I need all four exports?"
268
+
269
+ No.
270
+ Choose what matches your app runtime:
271
+
272
+ 1. Node-only package: `baseConfig + nodeConfig`
273
+ 2. Browser-only app: `baseConfig + webConfig`
274
+ 3. Vue SPA: `baseConfig + webConfig + vueConfig`
275
+ 4. Full-stack Vue app: `baseConfig + webConfig + nodeConfig + vueConfig`
276
+
277
+ ### "Can I override a rule in one app?"
278
+
279
+ Yes. Add an override block after the shared presets in that app config.
280
+
281
+ ### "Why not put ignore patterns in this package?"
282
+
283
+ Because ignore patterns are usually app-specific and change per app structure.
284
+
285
+ ---
286
+
287
+ ## 9) Troubleshooting
288
+
289
+ ### `window is not defined` in frontend files
290
+
291
+ Cause:
292
+ `webConfig` is missing.
293
+
294
+ Fix:
295
+ Add `...webConfig` to `eslint.config.mjs`.
296
+
297
+ ### `process is not defined` in backend files
298
+
299
+ Cause:
300
+ `nodeConfig` is missing.
301
+
302
+ Fix:
303
+ Add `...nodeConfig`.
304
+
305
+ ### `.cjs` files lint with module syntax issues
306
+
307
+ Cause:
308
+ No CommonJS override.
309
+
310
+ Fix:
311
+ Ensure `nodeConfig` is included (it adds the `.cjs` override).
312
+
313
+ ### Vue template/style rules feel too strict for your app
314
+
315
+ Cause:
316
+ You need local policy differences.
317
+
318
+ Fix:
319
+ Add app-level rule overrides after shared presets.
320
+
321
+ ---
322
+
323
+ ## Summary
324
+
325
+ `@jskit-ai/config-eslint` gives shared, practical lint presets for monorepo apps.
326
+
327
+ 1. Use shared presets for consistency.
328
+ 2. Keep app-specific policy in each app config.
329
+ 3. Compose only the presets each app actually needs.
package/base.js ADDED
@@ -0,0 +1,16 @@
1
+ import js from "@eslint/js";
2
+
3
+ const SOURCE_FILES = "**/*.{js,mjs,cjs,vue}";
4
+
5
+ const baseConfig = Object.freeze([
6
+ js.configs.recommended,
7
+ {
8
+ files: [SOURCE_FILES],
9
+ languageOptions: {
10
+ ecmaVersion: "latest",
11
+ sourceType: "module"
12
+ }
13
+ }
14
+ ]);
15
+
16
+ export { baseConfig };
package/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { baseConfig } from "./base.js";
2
+ export { nodeConfig } from "./node.js";
3
+ export { webConfig } from "./web.js";
4
+ export { vueConfig } from "./vue.js";
package/node.js ADDED
@@ -0,0 +1,25 @@
1
+ import globals from "globals";
2
+
3
+ const SOURCE_FILES = "**/*.{js,mjs,cjs,vue}";
4
+
5
+ const nodeConfig = Object.freeze([
6
+ {
7
+ files: [SOURCE_FILES],
8
+ languageOptions: {
9
+ globals: {
10
+ ...globals.node
11
+ }
12
+ }
13
+ },
14
+ {
15
+ files: ["**/*.cjs"],
16
+ languageOptions: {
17
+ sourceType: "commonjs",
18
+ globals: {
19
+ ...globals.node
20
+ }
21
+ }
22
+ }
23
+ ]);
24
+
25
+ export { nodeConfig };
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@jskit-ai/config-eslint",
3
+ "version": "0.1.0",
4
+ "description": "Shared flat ESLint presets for JSKIT projects.",
5
+ "type": "module",
6
+ "files": [
7
+ "base.js",
8
+ "index.js",
9
+ "node.js",
10
+ "web.js",
11
+ "vue.js",
12
+ "README.md"
13
+ ],
14
+ "scripts": {
15
+ "test": "node --test"
16
+ },
17
+ "exports": {
18
+ ".": "./index.js",
19
+ "./base": "./base.js",
20
+ "./node": "./node.js",
21
+ "./web": "./web.js",
22
+ "./vue": "./vue.js"
23
+ },
24
+ "dependencies": {
25
+ "@eslint/js": "^9.39.1",
26
+ "eslint-plugin-vue": "^10.5.1",
27
+ "globals": "^16.5.0"
28
+ },
29
+ "peerDependencies": {
30
+ "eslint": "^9.39.1"
31
+ },
32
+ "engines": {
33
+ "node": "20.x"
34
+ },
35
+ "publishConfig": {
36
+ "access": "public"
37
+ },
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "git+https://github.com/mobily-enterprises/jskit-ai.git",
41
+ "directory": "packages/tooling/config-eslint"
42
+ },
43
+ "bugs": {
44
+ "url": "https://github.com/mobily-enterprises/jskit-ai/issues"
45
+ },
46
+ "homepage": "https://github.com/mobily-enterprises/jskit-ai/tree/main/packages/tooling/config-eslint#readme",
47
+ "keywords": [
48
+ "jskit",
49
+ "eslint",
50
+ "config",
51
+ "lint"
52
+ ],
53
+ "devDependencies": {
54
+ "eslint": "^9.39.1"
55
+ }
56
+ }
package/vue.js ADDED
@@ -0,0 +1,19 @@
1
+ import vue from "eslint-plugin-vue";
2
+
3
+ const VUE_RELATED_FILES = "**/*.{js,mjs,cjs,vue}";
4
+
5
+ const vueConfig = Object.freeze([
6
+ ...vue.configs["flat/recommended"],
7
+ {
8
+ files: [VUE_RELATED_FILES],
9
+ rules: {
10
+ "vue/multi-word-component-names": "off",
11
+ "vue/max-attributes-per-line": "off",
12
+ "vue/singleline-html-element-content-newline": "off",
13
+ "vue/attributes-order": "off",
14
+ "vue/one-component-per-file": "off"
15
+ }
16
+ }
17
+ ]);
18
+
19
+ export { vueConfig };
package/web.js ADDED
@@ -0,0 +1,16 @@
1
+ import globals from "globals";
2
+
3
+ const SOURCE_FILES = "**/*.{js,mjs,cjs,vue}";
4
+
5
+ const webConfig = Object.freeze([
6
+ {
7
+ files: [SOURCE_FILES],
8
+ languageOptions: {
9
+ globals: {
10
+ ...globals.browser
11
+ }
12
+ }
13
+ }
14
+ ]);
15
+
16
+ export { webConfig };