@scayle/eslint-auto-explicit-import 0.2.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/CHANGELOG.md +1 -0
- package/LICENSE +21 -0
- package/README.md +58 -0
- package/dist/eslint-plugin-unimport.mjs +392 -0
- package/dist/module.d.mts +7 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +46 -0
- package/dist/types.d.mts +3 -0
- package/package.json +65 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# @scayle/eslint-auto-explicit-import
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 SCAYLE GmbH
|
|
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,58 @@
|
|
|
1
|
+
# @scayle/storefront-eslint-auto-explicit-import
|
|
2
|
+
|
|
3
|
+
An extension of the official `@nuxt/eslint` module to insert more explicit import statement
|
|
4
|
+
automatically using `eslint --fix` into a Nuxt-based SCAYLE Storefront project.
|
|
5
|
+
|
|
6
|
+
NOTE: Currently composables, utilities, helper functions and imported functions from packages will
|
|
7
|
+
be automatically inserted as imports. No components used within a `<template>` will be imported by it!
|
|
8
|
+
|
|
9
|
+
- Based on [nuxt-eslint-auto-explicit-import](https://github.com/antfu/nuxt-eslint-auto-explicit-import)
|
|
10
|
+
- Based on [eslint-plugin-unimport](https://github.com/antfu/eslint-plugin-unimport)
|
|
11
|
+
- [Official @nuxt/eslint module](https://eslint.nuxt.com/)
|
|
12
|
+
- [Official ESLint Documentation](https://eslint.org/docs/latest/)
|
|
13
|
+
|
|
14
|
+
## Example
|
|
15
|
+
|
|
16
|
+
- [Example Commit on eslint-flat-config-viewer](https://github.com/antfu/eslint-flat-config-viewer/commit/0f8000851b4ac0d7f3ea5e49963c6d7248303b7b)
|
|
17
|
+
|
|
18
|
+
## Details
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
Add local module to `nuxt.config.ts`:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
export default defineNuxtConfig({
|
|
26
|
+
modules: [
|
|
27
|
+
// Both are required
|
|
28
|
+
'@nuxt/eslint',
|
|
29
|
+
'@scayle/eslint-auto-explicit-import',
|
|
30
|
+
],
|
|
31
|
+
})
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Followed by adding a dedicated `eslint` flat config if none exists:
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
// eslint.config.mjs
|
|
38
|
+
import withNuxt from './nuxt/eslint.config.mjs'
|
|
39
|
+
|
|
40
|
+
export default withNuxt({
|
|
41
|
+
// Your ESLint config
|
|
42
|
+
})
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Running `eslint` should now throw errors if a source file does use auto-import.
|
|
46
|
+
Adding `--fix` allows for automatically inserting / fixing of missing imports.
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
# pnpm lint .
|
|
50
|
+
pnpm lint . --fix
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Troubleshooting
|
|
54
|
+
|
|
55
|
+
1. Should a Vue component not have a dedicated `<script>` tag with some content within,
|
|
56
|
+
it might be possible that the included local `eslint-plugin-unimport` fails with a
|
|
57
|
+
`range` undefined error.
|
|
58
|
+
In this case it is necessary to manually add the missing `<script>` tag with some dummy content.
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
import { dirname, isAbsolute, relative } from 'pathe'
|
|
2
|
+
import { ESLintUtils } from '@typescript-eslint/utils'
|
|
3
|
+
import { analyze } from '@typescript-eslint/scope-manager'
|
|
4
|
+
import Debug from 'debug'
|
|
5
|
+
|
|
6
|
+
// Based on <https://github.com/antfu/eslint-plugin-unimport>
|
|
7
|
+
|
|
8
|
+
const version = '0.0.3'
|
|
9
|
+
|
|
10
|
+
const createRule = ESLintUtils.RuleCreator(
|
|
11
|
+
() => 'https://github.com/antfu/eslint-plugin-unimport',
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
function betterRelative(from, to) {
|
|
15
|
+
// eslint-disable-next-line sonarjs/single-char-in-character-classes
|
|
16
|
+
const r = relative(from, to).replace(/\.[\w]+/g, '')
|
|
17
|
+
|
|
18
|
+
if (r.startsWith('../')) {
|
|
19
|
+
return r
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return `./${r}`
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const debug = Debug('unimport:eslint')
|
|
26
|
+
|
|
27
|
+
function createImportsListeners(context, imports, onImportEntry) {
|
|
28
|
+
let _scopeManager
|
|
29
|
+
let _importsMap
|
|
30
|
+
const importedNames = /* @__PURE__ */ new Set()
|
|
31
|
+
|
|
32
|
+
function getScopeManager() {
|
|
33
|
+
if (!_scopeManager) {
|
|
34
|
+
_scopeManager = analyze(context.sourceCode.ast, {
|
|
35
|
+
sourceType: 'module',
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
_scopeManager.globalScope?.variables.forEach((node) => {
|
|
39
|
+
importedNames.add(node.name)
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return _scopeManager
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function getImportsMap() {
|
|
47
|
+
if (!_importsMap) {
|
|
48
|
+
_importsMap = /* @__PURE__ */ new Map()
|
|
49
|
+
imports.forEach((i) => {
|
|
50
|
+
_importsMap.set(i.as || i.name, i)
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return _importsMap
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// eslint-disable-next-line sonarjs/cognitive-complexity
|
|
58
|
+
function checkId(node) {
|
|
59
|
+
if (typeof node.name !== 'string') {
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (importedNames.has(node.name)) {
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const importsMap = getImportsMap()
|
|
68
|
+
const item = importsMap.get(node.name)
|
|
69
|
+
|
|
70
|
+
if (!item) {
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (item.from === context.filename) {
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const scopeManager = getScopeManager()
|
|
79
|
+
|
|
80
|
+
if (importedNames.has(node.name)) {
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
let parent = node.parent
|
|
85
|
+
let currentScope = null
|
|
86
|
+
|
|
87
|
+
while (parent && !currentScope) {
|
|
88
|
+
currentScope = scopeManager.acquire(parent)
|
|
89
|
+
|
|
90
|
+
if (currentScope) {
|
|
91
|
+
break
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
parent = parent.parent
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (!currentScope) {
|
|
98
|
+
currentScope = scopeManager.globalScope
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const visited = /* @__PURE__ */ new Set()
|
|
102
|
+
|
|
103
|
+
while (true) {
|
|
104
|
+
if (!currentScope || visited.has(currentScope)) {
|
|
105
|
+
break
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
for (const ref of currentScope.variables) {
|
|
109
|
+
if (ref.name === node.name) {
|
|
110
|
+
return
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
visited.add(currentScope)
|
|
115
|
+
currentScope = currentScope.upper
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
importedNames.add(node.name)
|
|
119
|
+
onImportEntry(node, item)
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
Identifier(node) {
|
|
123
|
+
if (/Declaration|Specifier|Property/.test(node.parent.type)) {
|
|
124
|
+
return
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (
|
|
128
|
+
node.parent.type === 'MemberExpression' &&
|
|
129
|
+
node.parent.object !== node
|
|
130
|
+
) {
|
|
131
|
+
return
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
checkId(node)
|
|
135
|
+
},
|
|
136
|
+
ImportDeclaration(node) {
|
|
137
|
+
node.specifiers.forEach((s) => {
|
|
138
|
+
importedNames.add(s.local.name)
|
|
139
|
+
})
|
|
140
|
+
},
|
|
141
|
+
'Program:exit': function() {
|
|
142
|
+
const vueTemplate = context.sourceCode.ast.templateBody
|
|
143
|
+
|
|
144
|
+
if (!vueTemplate) {
|
|
145
|
+
return
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function visit(node) {
|
|
149
|
+
if (!node) {
|
|
150
|
+
return
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const expressionNode = node
|
|
154
|
+
|
|
155
|
+
switch (expressionNode.type) {
|
|
156
|
+
case 'Identifier':
|
|
157
|
+
checkId(expressionNode)
|
|
158
|
+
return
|
|
159
|
+
case 'MemberExpression':
|
|
160
|
+
visit(expressionNode.object)
|
|
161
|
+
return
|
|
162
|
+
case 'CallExpression':
|
|
163
|
+
visit(expressionNode.callee)
|
|
164
|
+
for (const arg of expressionNode.arguments) {
|
|
165
|
+
visit(arg)
|
|
166
|
+
}
|
|
167
|
+
return
|
|
168
|
+
case 'ConditionalExpression':
|
|
169
|
+
visit(expressionNode.test)
|
|
170
|
+
visit(expressionNode.consequent)
|
|
171
|
+
visit(expressionNode.alternate)
|
|
172
|
+
return
|
|
173
|
+
case 'FunctionExpression':
|
|
174
|
+
case 'ArrowFunctionExpression':
|
|
175
|
+
for (const param of expressionNode.params) {
|
|
176
|
+
visit(param)
|
|
177
|
+
}
|
|
178
|
+
visit(expressionNode.body)
|
|
179
|
+
return
|
|
180
|
+
case 'LogicalExpression':
|
|
181
|
+
case 'BinaryExpression':
|
|
182
|
+
visit(expressionNode.left)
|
|
183
|
+
visit(expressionNode.right)
|
|
184
|
+
return
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
switch (node.type) {
|
|
188
|
+
case 'VText':
|
|
189
|
+
return
|
|
190
|
+
case 'VExpressionContainer':
|
|
191
|
+
return visit(node.expression)
|
|
192
|
+
case 'VElement':
|
|
193
|
+
for (const attr of node.startTag.attributes) {
|
|
194
|
+
visit(attr)
|
|
195
|
+
}
|
|
196
|
+
for (const child of node.children) {
|
|
197
|
+
visit(child)
|
|
198
|
+
}
|
|
199
|
+
return
|
|
200
|
+
case 'VAttribute':
|
|
201
|
+
visit(node.value)
|
|
202
|
+
return
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if ('children' in node) {
|
|
206
|
+
for (const child of node.children) {
|
|
207
|
+
visit(child)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if ('body' in node) {
|
|
214
|
+
visit(node.body)
|
|
215
|
+
|
|
216
|
+
return
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
{
|
|
220
|
+
const { tokens, parent, range, loc, ...rest } = node
|
|
221
|
+
debug('Unknown VNode', rest)
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
visit(vueTemplate)
|
|
226
|
+
},
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const importPathDirNames = [
|
|
231
|
+
'/node_modules/',
|
|
232
|
+
'/packages/storefront-nuxt/',
|
|
233
|
+
'/packages/omnichannel-nuxt/', // Package needs to export appropriate `#omnichannel/composables` alias first
|
|
234
|
+
]
|
|
235
|
+
|
|
236
|
+
const validDirNames = {
|
|
237
|
+
storefrontNuxt: ['@scayle/storefront-nuxt', '/packages/storefront-nuxt'],
|
|
238
|
+
omnichannelNuxt: ['@scayle/omnichannel-nuxt', '/packages/omnichannel-nuxt'],
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Mapping normalized import paths of packages to pure package imports
|
|
242
|
+
// to avoid "Nuxt Build Error: [vite:load-fallback] Could not load (...)" if
|
|
243
|
+
// path can not properly be resolved within package dist directory.
|
|
244
|
+
const importsMap = {
|
|
245
|
+
'vue-i18n/dist/vue-i18n': 'vue-i18n',
|
|
246
|
+
'@nuxtjs/i18n/dist/runtime/composables/index': '#i18n', // https://github.com/nuxt-modules/i18n/blob/main/package.json#L34C6-L34C11
|
|
247
|
+
'nuxt/dist/pages/runtime/composables': '#imports', // Needs to be imported through #imports to properly work with TypeScript in the Nuxt context
|
|
248
|
+
'nuxt-jsonld/dist/runtime/composable': '#imports', // Needs to be imported through #imports to properly work with TypeScript in the Nuxt context
|
|
249
|
+
'@nuxt/image/dist/runtime/composables': '#imports', // Needs to be imported through #imports to properly work with TypeScript in the Nuxt context
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const transformPathToImport = (itemFrom, dirName) => {
|
|
253
|
+
const partialPath = itemFrom.split(dirName)[1]
|
|
254
|
+
|
|
255
|
+
// We check if we're trying to import composables from `@scayle/storefront-nuxt`
|
|
256
|
+
// or `@scayle/omnichannel-nuxt` and transform the import to their respective
|
|
257
|
+
// allowed import path or alias.
|
|
258
|
+
// NOTE: If a Nuxt project is part of a mono-repo setup and some of its used packages
|
|
259
|
+
// are located within the root repo, the package resolution using `mlly` will not
|
|
260
|
+
// resolve to a node_modules packages, but to the local package within the repository.
|
|
261
|
+
// https://github.com/unjs/mlly/issues/158
|
|
262
|
+
// For this reason we include a workaround that is able to check if we're within the
|
|
263
|
+
// mono-repo setup and transform the import paths appropriately.
|
|
264
|
+
if (
|
|
265
|
+
validDirNames.storefrontNuxt.some((element) => itemFrom.includes(element))
|
|
266
|
+
) {
|
|
267
|
+
return '#storefront/composables'
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (
|
|
271
|
+
validDirNames.omnichannelNuxt.some((element) => itemFrom.includes(element))
|
|
272
|
+
) {
|
|
273
|
+
return '#omnichannel/composables'
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// `nuxt-module-builder@0.7.0` changed the file extension for files within
|
|
277
|
+
// the build `/dist/runtime/` directory from `.mjs` to `.js`.
|
|
278
|
+
// https://github.com/nuxt/module-builder/commit/dbd05bb
|
|
279
|
+
const normalizedImportPath = partialPath.replace(/mjs|js/gi, '')
|
|
280
|
+
|
|
281
|
+
return importsMap[normalizedImportPath] ?? normalizedImportPath
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const createImportPaths = (item, context, srcAlias = '~') => {
|
|
285
|
+
const relativePath = betterRelative(
|
|
286
|
+
dirname(context.physicalFilename),
|
|
287
|
+
item.from,
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
if (!isAbsolute(item.from)) {
|
|
291
|
+
return item.from
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// We're checking if the item.from path contains one of the relevant directory names
|
|
295
|
+
// that we want to have transformed to a "plain" package import or alias import instead.
|
|
296
|
+
const dirName = importPathDirNames.find((name) => relativePath.includes(name))
|
|
297
|
+
|
|
298
|
+
if (dirName) {
|
|
299
|
+
return transformPathToImport(relativePath, dirName)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return `${srcAlias}/${relativePath.replaceAll('../', '')}`
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const autoInsert = createRule({
|
|
306
|
+
name: 'auto-insert',
|
|
307
|
+
meta: {
|
|
308
|
+
type: 'problem',
|
|
309
|
+
docs: {
|
|
310
|
+
description: 'Auto insert missing imports from unimport registry',
|
|
311
|
+
},
|
|
312
|
+
messages: {
|
|
313
|
+
missingImport:
|
|
314
|
+
`Unimport entry '{{name}}' from '{{from}}' is not imported.`,
|
|
315
|
+
},
|
|
316
|
+
schema: [{ type: 'array', items: { type: 'any' } }],
|
|
317
|
+
fixable: 'code',
|
|
318
|
+
},
|
|
319
|
+
defaultOptions: [],
|
|
320
|
+
create(context) {
|
|
321
|
+
return createImportsListeners(
|
|
322
|
+
context,
|
|
323
|
+
context.options[0] || [],
|
|
324
|
+
(node, item) => {
|
|
325
|
+
context.report({
|
|
326
|
+
node,
|
|
327
|
+
messageId: 'missingImport',
|
|
328
|
+
data: {
|
|
329
|
+
name: item.name,
|
|
330
|
+
from: createImportPaths(item, context),
|
|
331
|
+
},
|
|
332
|
+
fix(fixer) {
|
|
333
|
+
const resolvedFrom = createImportPaths(item, context)
|
|
334
|
+
const body = context.sourceCode.ast.body
|
|
335
|
+
|
|
336
|
+
let importName = ''
|
|
337
|
+
|
|
338
|
+
if (item.name === '*') {
|
|
339
|
+
importName = `* as ${item.as}`
|
|
340
|
+
} else if (item.name === 'default') {
|
|
341
|
+
// Default exports should be imported without curly braces
|
|
342
|
+
importName = item.as || item.name
|
|
343
|
+
} else if (!item.as || item.name === item.as) {
|
|
344
|
+
// Named exports should be imported with curly braces
|
|
345
|
+
importName = `{ ${item.name} }`
|
|
346
|
+
} else {
|
|
347
|
+
// Named exports with aliases should be imported with curly braces
|
|
348
|
+
importName = `{ ${item.name} as ${item.as} }`
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
return fixer.insertTextBefore(
|
|
352
|
+
body[0],
|
|
353
|
+
`import ${importName} from '${resolvedFrom}'
|
|
354
|
+
`,
|
|
355
|
+
)
|
|
356
|
+
},
|
|
357
|
+
})
|
|
358
|
+
},
|
|
359
|
+
)
|
|
360
|
+
},
|
|
361
|
+
})
|
|
362
|
+
|
|
363
|
+
const plugin = {
|
|
364
|
+
meta: {
|
|
365
|
+
name: 'unimport',
|
|
366
|
+
version,
|
|
367
|
+
},
|
|
368
|
+
rules: {
|
|
369
|
+
'auto-insert': autoInsert,
|
|
370
|
+
},
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function createAutoInsert(options) {
|
|
374
|
+
return {
|
|
375
|
+
name: 'unimport:auto-insert',
|
|
376
|
+
plugins: {
|
|
377
|
+
unimport: plugin,
|
|
378
|
+
},
|
|
379
|
+
files: options.include ?? [
|
|
380
|
+
'**/*.ts',
|
|
381
|
+
'**/*.(c|m)js',
|
|
382
|
+
'**/*.(m|c)?tsx?',
|
|
383
|
+
'**/*.vue',
|
|
384
|
+
],
|
|
385
|
+
ignores: options.exclude ?? ['**/*.mdx?/**'],
|
|
386
|
+
rules: {
|
|
387
|
+
'unimport/auto-insert': ['error', options.imports],
|
|
388
|
+
},
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
export { createAutoInsert, plugin as default }
|
package/dist/module.json
ADDED
package/dist/module.mjs
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { defineNuxtModule, createResolver, logger } from '@nuxt/kit';
|
|
2
|
+
|
|
3
|
+
const module = defineNuxtModule({
|
|
4
|
+
meta: {
|
|
5
|
+
name: "storefront-eslint-auto-explicit-import"
|
|
6
|
+
},
|
|
7
|
+
setup(_, nuxt) {
|
|
8
|
+
const { resolve } = createResolver(import.meta.url);
|
|
9
|
+
let unimport;
|
|
10
|
+
nuxt.hook("imports:context", (ctx) => {
|
|
11
|
+
unimport = ctx;
|
|
12
|
+
});
|
|
13
|
+
nuxt.hook("eslint:config:addons", (addons) => {
|
|
14
|
+
addons.push({
|
|
15
|
+
name: "storefront-eslint-auto-explicit-import",
|
|
16
|
+
async getConfigs() {
|
|
17
|
+
if (!unimport) {
|
|
18
|
+
logger.warn(
|
|
19
|
+
"unimport is not ready for storefront-eslint-auto-explicit-import"
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
imports: [
|
|
24
|
+
{
|
|
25
|
+
from: resolve("./eslint-plugin-unimport.mjs"),
|
|
26
|
+
name: "createAutoInsert"
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
configs: [
|
|
30
|
+
[
|
|
31
|
+
"// storefront-eslint-auto-explicit-import",
|
|
32
|
+
"createAutoInsert({",
|
|
33
|
+
` imports: ${JSON.stringify(
|
|
34
|
+
await unimport?.getImports() || []
|
|
35
|
+
)}`,
|
|
36
|
+
"})"
|
|
37
|
+
].join("\n")
|
|
38
|
+
]
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
export { module as default };
|
package/dist/types.d.mts
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@scayle/eslint-auto-explicit-import",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Automatically add explicit imports to ESLint",
|
|
5
|
+
"author": "SCAYLE Commerce Engine",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public",
|
|
9
|
+
"registry": "https://registry.npmjs.org/"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"url": "git+https://github.com/scayle/eslint-auto-explicit-import.git"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"eslint",
|
|
16
|
+
"eslintplugin",
|
|
17
|
+
"eslint-plugin",
|
|
18
|
+
"import"
|
|
19
|
+
],
|
|
20
|
+
"main": "./dist/module.mjs",
|
|
21
|
+
"type": "module",
|
|
22
|
+
"files": [
|
|
23
|
+
"CHANGELOG.md",
|
|
24
|
+
"dist/**",
|
|
25
|
+
"LICENSE"
|
|
26
|
+
],
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/module.d.mts",
|
|
30
|
+
"default": "./dist/module.mjs"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"debug": "4.4.1",
|
|
35
|
+
"pathe": "2.0.3"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@nuxt/kit": "3.16.2",
|
|
39
|
+
"@typescript-eslint/scope-manager": "8.36.0",
|
|
40
|
+
"@typescript-eslint/utils": "8.36.0",
|
|
41
|
+
"dprint": "0.50.1",
|
|
42
|
+
"eslint": "9.31.0",
|
|
43
|
+
"typescript": "5.8.3",
|
|
44
|
+
"unbuild": "3.5.0",
|
|
45
|
+
"unimport": "0.1.2",
|
|
46
|
+
"@scayle/eslint-config-storefront": "4.5.14"
|
|
47
|
+
},
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">= 20.0.0"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"@nuxt/kit": ">=3.13.0"
|
|
53
|
+
},
|
|
54
|
+
"volta": {
|
|
55
|
+
"node": "22.17.0"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"build": "nuxt-module-build build",
|
|
59
|
+
"lint": "eslint .",
|
|
60
|
+
"lint:ci": "eslint . --format gitlab",
|
|
61
|
+
"format": "dprint check",
|
|
62
|
+
"format:fix": "dprint fmt",
|
|
63
|
+
"typecheck": "tsc"
|
|
64
|
+
}
|
|
65
|
+
}
|