@dxup/nuxt 0.2.2 → 0.3.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 CHANGED
@@ -11,21 +11,23 @@ This is a TypeScript plugin that improves Nuxt DX.
11
11
 
12
12
  ## Installation
13
13
 
14
- ```bash
15
- pnpm i -D @dxup/nuxt
16
- ```
14
+ *No installation is required if you are using Nuxt 4.2 or above.*
17
15
 
18
16
  ## Usage
19
17
 
20
- Add the following to your `nuxt.config.ts`:
18
+ 1. Have `@dxup/unimport` installed as a dependency if you haven't enabled the `shamefullyHoist` option with pnpm workspace.
21
19
 
22
- ```ts
23
- export default defineNuxtConfig({
24
- modules: [
25
- "@dxup/nuxt",
26
- ],
27
- });
28
- ```
20
+ 2. Add the following to your `nuxt.config.ts`:
21
+
22
+ ```ts
23
+ export default defineNuxtConfig({
24
+ experimental: {
25
+ typescriptPlugin: true,
26
+ },
27
+ });
28
+ ```
29
+
30
+ 3. Run `nuxt prepare` and restart the tsserver.
29
31
 
30
32
  ## Features
31
33
 
@@ -73,4 +75,12 @@ Go to definition for runtime config.
73
75
 
74
76
  ### 5. unimport
75
77
 
78
+ Find references for SFC on `<template>`.
79
+
80
+ ```vue
81
+ ....<template>
82
+ <!-- ^^^^^^^^ -->
83
+ </template>
84
+ ```
85
+
76
86
  Please refer to the [@dxup/unimport](/packages/unimport) package for more details.
package/dist/module.d.mts CHANGED
@@ -27,9 +27,22 @@ interface ModuleOptions {
27
27
  * Whether to enable enhanced navigation for auto imported APIs.
28
28
  * @default true
29
29
  */
30
- unimport?: boolean;
30
+ unimport?: boolean | {
31
+ /**
32
+ * Whether to enable Find References for SFC on `<template>`.
33
+ */
34
+ componentReferences: boolean;
35
+ };
31
36
  };
32
37
  }
33
- declare const _default: _nuxt_schema0.NuxtModule<ModuleOptions, ModuleOptions, false>;
38
+ declare const _default: _nuxt_schema0.NuxtModule<ModuleOptions, {
39
+ features: {
40
+ components: true;
41
+ importGlob: true;
42
+ nitroRoutes: true;
43
+ runtimeConfig: true;
44
+ unimport: true;
45
+ };
46
+ }, true>;
34
47
  //#endregion
35
48
  export { ModuleOptions, _default as default };
package/dist/module.mjs CHANGED
@@ -64,7 +64,7 @@ async function onComponentsRename(nuxt, { fileName, references }) {
64
64
 
65
65
  //#endregion
66
66
  //#region src/module/index.ts
67
- var module_default = defineNuxtModule({
67
+ var module_default = defineNuxtModule().with({
68
68
  meta: {
69
69
  name,
70
70
  configKey: "dxup"
@@ -87,13 +87,19 @@ var module_default = defineNuxtModule({
87
87
  filename: "dxup/data.json",
88
88
  write: true,
89
89
  getContents({ nuxt: nuxt$1 }) {
90
- const nitro = useNitro();
90
+ const nitroRoutes = useNitro().scannedHandlers.reduce((acc, item) => {
91
+ if (item.route && item.method) (acc[item.route] ??= {})[item.method] = item.handler;
92
+ return acc;
93
+ }, {});
91
94
  const data = {
92
95
  buildDir: nuxt$1.options.buildDir,
93
96
  publicDir: nuxt$1.options.dir.public,
94
97
  configFiles: [...nuxt$1.options._nuxtConfigFiles, ...nuxt$1.options._layers.map((layer) => layer._configFile).filter(Boolean)],
95
- nitroRoutes: Object.fromEntries(nitro.scannedHandlers.filter((item) => item.route).map((item) => [`${item.route}+${item.method ?? "get"}`, item.handler])),
96
- features: options.features
98
+ nitroRoutes,
99
+ features: {
100
+ ...options.features,
101
+ unimport: { componentReferences: typeof options.features.unimport === "object" ? options.features.unimport.componentReferences : options.features.unimport }
102
+ }
97
103
  };
98
104
  return JSON.stringify(data, null, 2);
99
105
  }
@@ -1,3 +1,20 @@
1
+ //#region rolldown:runtime
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (all, symbols) => {
4
+ let target = {};
5
+ for (var name in all) {
6
+ __defProp(target, name, {
7
+ get: all[name],
8
+ enumerable: true
9
+ });
10
+ }
11
+ if (symbols) {
12
+ __defProp(target, Symbol.toStringTag, { value: "Module" });
13
+ }
14
+ return target;
15
+ };
16
+
17
+ //#endregion
1
18
  let node_fs_promises = require("node:fs/promises");
2
19
  let pathe = require("pathe");
3
20
  let tinyglobby = require("tinyglobby");
@@ -24,7 +41,8 @@ const initialValue = {
24
41
  components: true,
25
42
  importGlob: true,
26
43
  nitroRoutes: true,
27
- runtimeConfig: true
44
+ runtimeConfig: true,
45
+ unimport: { componentReferences: true }
28
46
  }
29
47
  };
30
48
  const callbacks = {};
@@ -46,12 +64,81 @@ function createData(ts, info) {
46
64
  return data;
47
65
  }
48
66
 
67
+ //#endregion
68
+ //#region src/typescript/utils.ts
69
+ function isVueVirtualCode(code) {
70
+ return code?.languageId === "vue";
71
+ }
72
+ function toSourceSpan(language, fileName, textSpan) {
73
+ const sourceScript = language?.scripts.get(fileName);
74
+ if (!sourceScript?.generated) return;
75
+ const serviceScript = sourceScript.generated.languagePlugin.typescript?.getServiceScript(sourceScript.generated.root);
76
+ if (!serviceScript) return;
77
+ const map = language.maps.get(serviceScript.code, sourceScript);
78
+ const leadingOffset = sourceScript.snapshot.getLength();
79
+ for (const [start, end] of map.toSourceRange(textSpan.start - leadingOffset, textSpan.start + textSpan.length - leadingOffset, false)) return {
80
+ start,
81
+ length: end - start
82
+ };
83
+ }
84
+ function withVirtualOffset(language, sourceScript, position, method) {
85
+ const serviceScript = sourceScript.generated.languagePlugin.typescript?.getServiceScript(sourceScript.generated.root);
86
+ if (!serviceScript) return;
87
+ const map = language.maps.get(serviceScript.code, sourceScript);
88
+ const leadingOffset = sourceScript.snapshot.getLength();
89
+ const offset = 1145141919810;
90
+ const mapping = {
91
+ sourceOffsets: [offset],
92
+ generatedOffsets: [position - leadingOffset],
93
+ lengths: [0],
94
+ data: {
95
+ completion: true,
96
+ navigation: true,
97
+ semantic: true,
98
+ verification: true
99
+ }
100
+ };
101
+ const original = map.toGeneratedLocation;
102
+ map.toGeneratedLocation = function* (sourceOffset, ...args) {
103
+ if (sourceOffset === offset) yield [mapping.generatedOffsets[0], mapping];
104
+ yield* original.call(this, sourceOffset, ...args);
105
+ };
106
+ try {
107
+ return method(offset);
108
+ } finally {
109
+ map.toGeneratedLocation = original;
110
+ }
111
+ }
112
+
113
+ //#endregion
114
+ //#region src/typescript/features/findReferences.ts
115
+ var findReferences_exports = /* @__PURE__ */ __export({ postprocess: () => postprocess$1 });
116
+ function postprocess$1(context, language, findReferences) {
117
+ const { ts, info } = context;
118
+ return (...args) => {
119
+ const result = findReferences(...args);
120
+ if (!result?.length) {
121
+ const sourceScript = language.scripts.get(args[0]);
122
+ const root = sourceScript?.generated?.root;
123
+ if (!isVueVirtualCode(root)) return;
124
+ const start = (root.sfc.template?.start ?? Infinity) + 1;
125
+ if (args[1] < start || args[1] > start + 8) return;
126
+ const sourceFile = info.languageService.getProgram().getSourceFile(args[0]);
127
+ if (!sourceFile) return;
128
+ for (const statement of sourceFile.statements) if (ts.isExportAssignment(statement)) return withVirtualOffset(language, sourceScript, statement.getChildAt(1).getStart(sourceFile), (position) => findReferences(args[0], position));
129
+ return;
130
+ }
131
+ return result;
132
+ };
133
+ }
134
+
49
135
  //#endregion
50
136
  //#region src/typescript/features/findRenameLocations.ts
51
- function findRenameLocations(context, findRenameLocations$1) {
137
+ var findRenameLocations_exports = /* @__PURE__ */ __export({ preprocess: () => preprocess$2 });
138
+ function preprocess$2(context, findRenameLocations) {
52
139
  const { data } = context;
53
140
  return (...args) => {
54
- return findRenameLocations$1(...args)?.filter((edit) => {
141
+ return findRenameLocations(...args)?.filter((edit) => {
55
142
  return !edit.fileName.startsWith(data.buildDir);
56
143
  });
57
144
  };
@@ -87,15 +174,46 @@ function isTextSpanWithin(node, textSpan, sourceFile) {
87
174
 
88
175
  //#endregion
89
176
  //#region src/typescript/features/getDefinitionAndBoundSpan.ts
177
+ var getDefinitionAndBoundSpan_exports = /* @__PURE__ */ __export({
178
+ postprocess: () => postprocess,
179
+ preprocess: () => preprocess$1
180
+ });
90
181
  const fetchFunctions = new Set([
91
182
  "$fetch",
92
183
  "useFetch",
93
184
  "useLazyFetch"
94
185
  ]);
95
- function getDefinitionAndBoundSpan(context, getDefinitionAndBoundSpan$1) {
186
+ function postprocess(context, language, getDefinitionAndBoundSpan) {
187
+ const { ts } = context;
188
+ return (...args) => {
189
+ const result = getDefinitionAndBoundSpan(...args);
190
+ if (!result?.definitions?.length) {
191
+ const root = language.scripts.get(args[0])?.generated?.root;
192
+ if (!isVueVirtualCode(root)) return result;
193
+ const textSpan = {
194
+ start: (root.sfc.template?.start ?? Infinity) + 1,
195
+ length: 8
196
+ };
197
+ if (args[1] >= textSpan.start && args[1] <= textSpan.start + textSpan.length) return {
198
+ textSpan,
199
+ definitions: [{
200
+ fileName: args[0],
201
+ textSpan,
202
+ kind: ts.ScriptElementKind.scriptElement,
203
+ name: args[0],
204
+ containerKind: ts.ScriptElementKind.unknown,
205
+ containerName: ""
206
+ }]
207
+ };
208
+ return result;
209
+ }
210
+ return result;
211
+ };
212
+ }
213
+ function preprocess$1(context, getDefinitionAndBoundSpan) {
96
214
  const { ts, info, data } = context;
97
215
  return (...args) => {
98
- const result = getDefinitionAndBoundSpan$1(...args);
216
+ const result = getDefinitionAndBoundSpan(...args);
99
217
  if (!result) {
100
218
  const program$1 = info.languageService.getProgram();
101
219
  const sourceFile = program$1.getSourceFile(args[0]);
@@ -187,8 +305,11 @@ function visitNitroRoutes(ts, data, checker, sourceFile, node, position) {
187
305
  }
188
306
  const paths = [];
189
307
  if (routeType?.isStringLiteral()) {
190
- for (const type of methodType?.isUnion() ? methodType.types : [methodType]) if (type?.isStringLiteral()) {
191
- const path = data.nitroRoutes[`${routeType.value}+${type.value}`];
308
+ const alternatives = data.nitroRoutes[routeType.value] ?? {};
309
+ const methods = [];
310
+ for (const type of methodType?.isUnion() ? methodType.types : [methodType]) if (type?.isStringLiteral()) methods.push(type.value);
311
+ for (const method of methods.length ? methods : Object.keys(alternatives)) {
312
+ const path = alternatives[method];
192
313
  if (path !== void 0) paths.push(path);
193
314
  }
194
315
  }
@@ -289,27 +410,13 @@ function* forwardRuntimeConfig(context, definition, path) {
289
410
  }
290
411
  }
291
412
 
292
- //#endregion
293
- //#region src/typescript/utils.ts
294
- function toSourceSpan(language, fileName, textSpan) {
295
- const sourceScript = language?.scripts.get(fileName);
296
- if (!sourceScript?.generated) return;
297
- const serviceScript = sourceScript.generated.languagePlugin.typescript?.getServiceScript(sourceScript.generated.root);
298
- if (!serviceScript) return;
299
- const map = language.maps.get(serviceScript.code, sourceScript);
300
- const leadingOffset = sourceScript.snapshot.getLength();
301
- for (const [start, end] of map.toSourceRange(textSpan.start - leadingOffset, textSpan.start + textSpan.length - leadingOffset, false)) return {
302
- start,
303
- length: end - start
304
- };
305
- }
306
-
307
413
  //#endregion
308
414
  //#region src/typescript/features/getEditsForFileRename.ts
309
- function getEditsForFileRename(context, getEditsForFileRename$1) {
415
+ var getEditsForFileRename_exports = /* @__PURE__ */ __export({ preprocess: () => preprocess });
416
+ function preprocess(context, getEditsForFileRename) {
310
417
  const { ts, info, data, server } = context;
311
418
  return (...args) => {
312
- const result = getEditsForFileRename$1(...args);
419
+ const result = getEditsForFileRename(...args);
313
420
  if (!result?.length) return result;
314
421
  const program = info.languageService.getProgram();
315
422
  const references = {};
@@ -346,22 +453,38 @@ function getEditsForFileRename(context, getEditsForFileRename$1) {
346
453
  const plugin = (module$1) => {
347
454
  const { typescript: ts } = module$1;
348
455
  return { create(info) {
456
+ const data = createData(ts, info);
349
457
  const context = {
350
458
  ts,
351
459
  info,
352
- data: createData(ts, info),
460
+ data,
353
461
  server: createEventServer(info)
354
462
  };
355
463
  setTimeout(() => {
356
- context.language = (info.project.__vue__ ?? info.project["program"]?.__vue__)?.language;
357
- }, 500);
464
+ context.language = info.project.__vue__?.language;
465
+ if (!context.language || !data.features.unimport.componentReferences) return;
466
+ const languageService = info.project.getLanguageService();
467
+ const methods = {};
468
+ for (const [key, method] of [["findReferences", findReferences_exports], ["getDefinitionAndBoundSpan", getDefinitionAndBoundSpan_exports]]) {
469
+ const original = languageService[key];
470
+ methods[key] = method.postprocess(context, context.language, original);
471
+ }
472
+ info.project["languageService"] = new Proxy(languageService, {
473
+ get(target, p, receiver) {
474
+ return methods[p] ?? Reflect.get(target, p, receiver);
475
+ },
476
+ set(...args) {
477
+ return Reflect.set(...args);
478
+ }
479
+ });
480
+ }, 0);
358
481
  for (const [key, method] of [
359
- ["findRenameLocations", findRenameLocations],
360
- ["getDefinitionAndBoundSpan", getDefinitionAndBoundSpan],
361
- ["getEditsForFileRename", getEditsForFileRename]
482
+ ["findRenameLocations", findRenameLocations_exports],
483
+ ["getDefinitionAndBoundSpan", getDefinitionAndBoundSpan_exports],
484
+ ["getEditsForFileRename", getEditsForFileRename_exports]
362
485
  ]) {
363
486
  const original = info.languageService[key];
364
- info.languageService[key] = method(context, original);
487
+ info.languageService[key] = method.preprocess(context, original);
365
488
  }
366
489
  return info.languageService;
367
490
  } };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dxup/nuxt",
3
3
  "type": "module",
4
- "version": "0.2.2",
4
+ "version": "0.3.0",
5
5
  "description": "TypeScript plugin for Nuxt",
6
6
  "author": "KazariEX",
7
7
  "license": "MIT",
@@ -16,18 +16,18 @@
16
16
  "dist"
17
17
  ],
18
18
  "dependencies": {
19
- "@nuxt/kit": "^4.2.1",
20
- "chokidar": "^4.0.3",
19
+ "@nuxt/kit": "^4.2.2",
20
+ "chokidar": "^5.0.0",
21
21
  "pathe": "^2.0.3",
22
22
  "tinyglobby": "^0.2.15",
23
23
  "@dxup/unimport": "^0.1.2"
24
24
  },
25
25
  "devDependencies": {
26
26
  "@dxup/shared": "",
27
- "@volar/language-core": "^2.4.23",
28
- "@volar/typescript": "^2.4.23",
29
- "@vue/language-core": "^3.1.3",
30
- "nuxt": "^4.2.1",
27
+ "@volar/language-core": "^2.4.26",
28
+ "@volar/typescript": "^2.4.26",
29
+ "@vue/language-core": "^3.1.8",
30
+ "nuxt": "^4.2.2",
31
31
  "typescript": "^5.9.3"
32
32
  },
33
33
  "scripts": {