@scayle/eslint-auto-explicit-import 0.2.1 → 0.4.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 CHANGED
@@ -1,5 +1,19 @@
1
1
  # @scayle/eslint-auto-explicit-import
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - This package is deprecated. Remove @scayle/eslint-auto-explicit-import from your Nuxt config and dependencies.
8
+
9
+ ## 0.3.0
10
+
11
+ ### Minor Changes
12
+
13
+ - All packages now require Node.js 22 or later, in line with the current Node.js LTS release schedule. See the [Node.js release schedule](https://nodejs.org/en/about/previous-releases#release-schedule) for details.
14
+
15
+ If your project is still running an older Node.js version, now is a good time to upgrade to Node.js 22 at minimum, or ideally Node.js 24, for the latest security patches and stability improvements.
16
+
3
17
  ## 0.2.1
4
18
 
5
19
  ### Patch Changes
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # @scayle/storefront-eslint-auto-explicit-import
2
2
 
3
+ > **Deprecated.** This package is deprecated. Remove @scayle/eslint-auto-explicit-import from your Nuxt config and dependencies.
4
+
3
5
  An extension of the official `@nuxt/eslint` module to insert more explicit import statement
4
6
  automatically using `eslint --fix` into a Nuxt-based SCAYLE Storefront project.
5
7
 
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@scayle/eslint-auto-explicit-import",
3
- "version": "0.2.1",
3
+ "version": "0.4.0",
4
4
  "description": "Automatically add explicit imports to ESLint",
5
+ "deprecated": "This package is deprecated and will be removed in a future release. Remove it from your dependencies and Nuxt config.",
5
6
  "author": "SCAYLE Commerce Engine",
6
7
  "license": "MIT",
7
8
  "publishConfig": {
@@ -35,18 +36,18 @@
35
36
  "pathe": "2.0.3"
36
37
  },
37
38
  "devDependencies": {
38
- "@nuxt/kit": "3.20.0",
39
- "@typescript-eslint/scope-manager": "8.50.0",
40
- "@typescript-eslint/utils": "8.50.0",
41
- "dprint": "0.50.2",
42
- "eslint": "9.39.2",
43
- "typescript": "5.9.3",
44
- "unbuild": "3.6.1",
45
- "unimport": "0.1.2",
46
- "@scayle/eslint-config-storefront": "4.7.18"
39
+ "@nuxt/eslint": "1.14.0",
40
+ "@nuxt/kit": "^3.21.7",
41
+ "@scayle/eslint-config-storefront": "^4.8.0",
42
+ "@typescript-eslint/scope-manager": "8.60.0",
43
+ "@typescript-eslint/utils": "8.60.0",
44
+ "@nuxt/module-builder": "1.0.2",
45
+ "eslint": "10.7.0",
46
+ "typescript": "6.0.3",
47
+ "unbuild": "3.6.1"
47
48
  },
48
49
  "engines": {
49
- "node": ">= 20.0.0"
50
+ "node": ">= 22.0.0"
50
51
  },
51
52
  "peerDependencies": {
52
53
  "@nuxt/kit": ">=3.13.0"
@@ -55,8 +56,6 @@
55
56
  "build": "nuxt-module-build build",
56
57
  "lint": "eslint .",
57
58
  "lint:ci": "eslint . --format gitlab",
58
- "format": "dprint check",
59
- "format:fix": "dprint fmt",
60
59
  "typecheck": "tsc"
61
60
  }
62
61
  }
@@ -1,392 +0,0 @@
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.d.mts DELETED
@@ -1,7 +0,0 @@
1
- import * as _nuxt_schema from '@nuxt/schema';
2
-
3
- type ModuleOptions = object;
4
- declare const _default: _nuxt_schema.NuxtModule<object, object, false>;
5
-
6
- export { _default as default };
7
- export type { ModuleOptions };
package/dist/module.json DELETED
@@ -1,9 +0,0 @@
1
- {
2
- "name": "storefront-eslint-auto-explicit-import",
3
- "configKey": "storefront-eslint-auto-explicit-import",
4
- "version": "0.2.1",
5
- "builder": {
6
- "@nuxt/module-builder": "1.0.2",
7
- "unbuild": "3.6.1"
8
- }
9
- }
package/dist/module.mjs DELETED
@@ -1,46 +0,0 @@
1
- import { defineNuxtModule, createResolver, logger } from '@nuxt/kit';
2
-
3
- const module$1 = 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$1 as default };
package/dist/types.d.mts DELETED
@@ -1,3 +0,0 @@
1
- export { default } from './module.mjs'
2
-
3
- export { type ModuleOptions } from './module.mjs'