@dxup/nuxt 0.0.4 → 0.0.5

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
@@ -4,12 +4,12 @@
4
4
  [![downloads](https://img.shields.io/npm/dm/@dxup/nuxt?color=007EC7&label=downloads)](https://www.npmjs.com/package/@dxup/nuxt)
5
5
  [![license](https://img.shields.io/npm/l/@dxup/nuxt?color=007EC7&label=license)](/LICENSE)
6
6
 
7
- This is a collection of TypeScript and Vue plugins that improves Nuxt DX.
7
+ This is a collection of TypeScript plugins that improves Nuxt DX.
8
8
 
9
9
  ## Features
10
10
 
11
11
  - Update references when renaming auto imported component files
12
- - Go to definition for nitro routes in data fetching methods within Vue files
12
+ - Go to definition for nitro routes in data fetching methods
13
13
  - Go to definition for runtime config
14
14
  - [@dxup/unimport](/packages/unimport)
15
15
 
package/dist/module.js CHANGED
@@ -77,20 +77,18 @@ var module_default = defineNuxtModule({
77
77
  },
78
78
  async setup(options, nuxt) {
79
79
  const pluginsTs = [{ name: "@dxup/nuxt" }];
80
- const pluginsVue = [];
81
- if (options.nitroRoutes) pluginsVue.push("@dxup/nuxt/vue/nitro-routes");
82
80
  if (options.unimport) pluginsTs.unshift({ name: "@dxup/unimport" });
83
81
  append(pluginsTs, nuxt.options, "typescript", "tsConfig", "compilerOptions");
84
82
  append(pluginsTs, nuxt.options.nitro, "typescript", "tsConfig", "compilerOptions");
85
83
  append(pluginsTs, nuxt.options, "typescript", "sharedTsConfig", "compilerOptions");
86
84
  append(pluginsTs, nuxt.options, "typescript", "nodeTsConfig", "compilerOptions");
87
- append(pluginsVue, nuxt.options, "typescript", "tsConfig", "vueCompilerOptions");
88
85
  addTemplate({
89
86
  filename: "dxup/data.json",
90
87
  write: true,
91
88
  getContents() {
92
89
  const data = {
93
90
  buildDir: nuxt.options.buildDir,
91
+ serverDir: nuxt.options.serverDir,
94
92
  configFiles: [...nuxt.options._nuxtConfigFiles, ...nuxt.options._layers.map((layer) => layer._configFile).filter(Boolean)],
95
93
  components: options.components,
96
94
  nitroRoutes: options.nitroRoutes,
@@ -21,7 +21,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
21
21
  }) : target, mod));
22
22
 
23
23
  //#endregion
24
- const require_src = require('./src-BfXMgjZD.cjs');
25
24
  let pathe = require("pathe");
26
25
  pathe = __toESM(pathe);
27
26
  let node_fs_promises = require("node:fs/promises");
@@ -30,49 +29,16 @@ node_fs_promises = __toESM(node_fs_promises);
30
29
  //#region src/event/server.ts
31
30
  function createEventServer(info) {
32
31
  const path = (0, pathe.join)(info.project.getCurrentDirectory(), "dxup/events.md");
33
- function write(key, data) {
34
- return (0, node_fs_promises.appendFile)(path, `\`\`\`json {${key}}\n${JSON.stringify(data, null, 2)}\n\`\`\`\n`).catch();
32
+ async function write(key, data) {
33
+ try {
34
+ await (0, node_fs_promises.appendFile)(path, `\`\`\`json {${key}}\n${JSON.stringify(data, null, 2)}\n\`\`\`\n`);
35
+ } catch {}
35
36
  }
36
37
  return { write };
37
38
  }
38
39
 
39
40
  //#endregion
40
- //#region src/typescript/index.ts
41
- const plugin = (module$1) => {
42
- const { typescript: ts } = module$1;
43
- return { create(info) {
44
- const currentDirectory = info.languageServiceHost.getCurrentDirectory();
45
- const path = (0, pathe.join)(currentDirectory, "dxup/data.json");
46
- const data = {
47
- buildDir: currentDirectory,
48
- configFiles: [],
49
- components: true,
50
- nitroRoutes: true,
51
- runtimeConfig: true,
52
- ...JSON.parse(ts.sys.readFile(path) ?? "{}")
53
- };
54
- const server = createEventServer(info);
55
- const context = {
56
- ts,
57
- info,
58
- data,
59
- server
60
- };
61
- setTimeout(() => {
62
- context.language = (info.project.__vue__ ?? info.project["program"]?.__vue__)?.language;
63
- }, 500);
64
- for (const [key, method] of [
65
- ["findRenameLocations", findRenameLocations.bind(null, context)],
66
- ["getDefinitionAndBoundSpan", getDefinitionAndBoundSpan.bind(null, context)],
67
- ["getEditsForFileRename", getEditsForFileRename.bind(null, context)]
68
- ]) {
69
- const original = info.languageService[key];
70
- info.languageService[key] = method(original);
71
- }
72
- return info.languageService;
73
- } };
74
- };
75
- var typescript_default = plugin;
41
+ //#region src/typescript/features/findRenameLocations.ts
76
42
  function findRenameLocations(context, findRenameLocations$1) {
77
43
  const { data } = context;
78
44
  return (...args) => {
@@ -81,10 +47,86 @@ function findRenameLocations(context, findRenameLocations$1) {
81
47
  });
82
48
  };
83
49
  }
50
+
51
+ //#endregion
52
+ //#region ../shared/src/index.ts
53
+ function* forEachTouchNode(ts, sourceFile, position) {
54
+ yield* binaryVisit(ts, sourceFile, sourceFile, position);
55
+ }
56
+ function* binaryVisit(ts, sourceFile, node, position) {
57
+ const nodes = [];
58
+ ts.forEachChild(node, (child) => {
59
+ nodes.push(child);
60
+ });
61
+ let left = 0;
62
+ let right = nodes.length - 1;
63
+ while (left <= right) {
64
+ const mid = Math.floor((left + right) / 2);
65
+ const node$1 = nodes[mid];
66
+ const start = node$1.getStart(sourceFile);
67
+ const end = node$1.getEnd();
68
+ if (position < start) right = mid - 1;
69
+ else if (position > end) left = mid + 1;
70
+ else {
71
+ yield node$1;
72
+ yield* binaryVisit(ts, sourceFile, node$1, position);
73
+ return;
74
+ }
75
+ }
76
+ }
77
+
78
+ //#endregion
79
+ //#region src/typescript/features/getDefinitionAndBoundSpan.ts
80
+ const fetchFunctions = new Set([
81
+ "$fetch",
82
+ "useFetch",
83
+ "useLazyFetch"
84
+ ]);
85
+ const nonApiRE = /^(?!\/api\/)/;
84
86
  function getDefinitionAndBoundSpan(context, getDefinitionAndBoundSpan$1) {
85
- const { info, data } = context;
87
+ const { ts, info, data } = context;
86
88
  return (...args) => {
87
89
  const result = getDefinitionAndBoundSpan$1(...args);
90
+ if (!result && data.nitroRoutes) {
91
+ const program$1 = info.languageService.getProgram();
92
+ const sourceFile = program$1.getSourceFile(args[0]);
93
+ if (!sourceFile) return;
94
+ const checker = program$1.getTypeChecker();
95
+ for (const node of forEachTouchNode(ts, sourceFile, args[1])) {
96
+ if (!ts.isCallExpression(node) || !ts.isIdentifier(node.expression) || !fetchFunctions.has(node.expression.text) || !node.arguments.length) continue;
97
+ const firstArg = node.arguments[0];
98
+ const start = firstArg.getStart(sourceFile);
99
+ const end = firstArg.getEnd();
100
+ if (args[1] < start || args[1] > end) continue;
101
+ const resolvedSignature = checker.getResolvedSignature(node);
102
+ if (!resolvedSignature) break;
103
+ const typeArguments = checker.getTypeArgumentsForResolvedSignature(resolvedSignature);
104
+ const routeType = typeArguments?.[2];
105
+ const methodtype = typeArguments?.[3];
106
+ if (!routeType?.isStringLiteral() || !methodtype?.isStringLiteral()) break;
107
+ const route = routeType.value.replace(nonApiRE, "/routes");
108
+ const method = methodtype.value;
109
+ const path = (0, pathe.join)(data.serverDir, `${route}.${method}.ts`);
110
+ return {
111
+ textSpan: {
112
+ start,
113
+ length: end - start
114
+ },
115
+ definitions: [{
116
+ fileName: path,
117
+ textSpan: {
118
+ start: 0,
119
+ length: 0
120
+ },
121
+ kind: ts.ScriptElementKind.scriptElement,
122
+ name: path,
123
+ containerKind: ts.ScriptElementKind.unknown,
124
+ containerName: ""
125
+ }]
126
+ };
127
+ }
128
+ return;
129
+ }
88
130
  if (!result?.definitions?.length) return result;
89
131
  const program = info.languageService.getProgram();
90
132
  const definitions = new Set(result.definitions);
@@ -93,8 +135,7 @@ function getDefinitionAndBoundSpan(context, getDefinitionAndBoundSpan$1) {
93
135
  const sourceFile = program.getSourceFile(definition.fileName);
94
136
  if (!sourceFile) continue;
95
137
  let result$1 = [];
96
- if (data.nitroRoutes && definition.fileName.endsWith("nitro-routes.d.ts")) result$1 = visitNitroRoutes(context, sourceFile, definition, getDefinitionAndBoundSpan$1);
97
- else if (data.runtimeConfig && definition.fileName.endsWith("runtime-config.d.ts")) result$1 = visitRuntimeConfig(context, sourceFile, definition);
138
+ if (data.runtimeConfig && definition.fileName.endsWith("runtime-config.d.ts")) result$1 = visitRuntimeConfig(context, sourceFile, definition);
98
139
  if (result$1?.length) {
99
140
  for (const definition$1 of result$1) definitions.add(definition$1);
100
141
  skippedDefinitions.push(definition);
@@ -107,32 +148,11 @@ function getDefinitionAndBoundSpan(context, getDefinitionAndBoundSpan$1) {
107
148
  };
108
149
  };
109
150
  }
110
- function visitNitroRoutes(context, sourceFile, definition, getDefinitionAndBoundSpan$1) {
111
- const { ts } = context;
112
- const definitions = [];
113
- for (const node of require_src.forEachNode(ts, sourceFile)) {
114
- if (!ts.isPropertySignature(node) || !node.type || !ts.isTypeLiteralNode(node.type)) continue;
115
- const { textSpan } = definition;
116
- const start = node.name.getStart(sourceFile);
117
- const end = node.name.getEnd();
118
- if (start !== textSpan.start || end - start !== textSpan.length) continue;
119
- for (const member of node.type.members) {
120
- if (!ts.isPropertySignature(member)) continue;
121
- const pos = (((((member.type?.typeArguments?.[0])?.typeArguments?.[0])?.typeArguments?.[0])?.typeArguments?.[0])?.qualifier)?.getStart(sourceFile);
122
- if (pos !== void 0) {
123
- const res = getDefinitionAndBoundSpan$1(definition.fileName, pos);
124
- if (res?.definitions?.length) definitions.push(...res.definitions);
125
- }
126
- }
127
- break;
128
- }
129
- return definitions;
130
- }
131
151
  function visitRuntimeConfig(context, sourceFile, definition) {
132
152
  const { ts } = context;
133
153
  let definitions = [];
134
154
  const path = [];
135
- require_src.walkNodes(ts, sourceFile, (node, next) => {
155
+ for (const node of forEachTouchNode(ts, sourceFile, definition.textSpan.start)) {
136
156
  let key;
137
157
  if (ts.isInterfaceDeclaration(node) && ts.isIdentifier(node.name)) key = node.name.text;
138
158
  else if (ts.isPropertySignature(node) && ts.isIdentifier(node.name)) {
@@ -143,13 +163,11 @@ function visitRuntimeConfig(context, sourceFile, definition) {
143
163
  if (start === textSpan.start && end - start === textSpan.length) {
144
164
  path.push(key);
145
165
  definitions = [...proxyRuntimeConfig(context, definition, path)];
146
- return;
166
+ break;
147
167
  }
148
168
  }
149
169
  if (key !== void 0) path.push(key);
150
- next();
151
- if (key !== void 0) path.pop();
152
- });
170
+ }
153
171
  return definitions;
154
172
  }
155
173
  function* proxyRuntimeConfig(context, definition, path) {
@@ -207,6 +225,24 @@ function* proxyRuntimeConfig(context, definition, path) {
207
225
  }
208
226
  }
209
227
  }
228
+
229
+ //#endregion
230
+ //#region src/typescript/utils.ts
231
+ function toSourceSpan(language, fileName, textSpan) {
232
+ const sourceScript = language?.scripts.get(fileName);
233
+ if (!sourceScript?.generated) return;
234
+ const serviceScript = sourceScript.generated.languagePlugin.typescript?.getServiceScript(sourceScript.generated.root);
235
+ if (!serviceScript) return;
236
+ const map = language.maps.get(serviceScript.code, sourceScript);
237
+ const leadingOffset = sourceScript.snapshot.getLength();
238
+ for (const [start, end] of map.toSourceRange(textSpan.start - leadingOffset, textSpan.start + textSpan.length - leadingOffset, false)) return {
239
+ start,
240
+ length: end - start
241
+ };
242
+ }
243
+
244
+ //#endregion
245
+ //#region src/typescript/features/getEditsForFileRename.ts
210
246
  function getEditsForFileRename(context, getEditsForFileRename$1) {
211
247
  const { ts, info, data, server } = context;
212
248
  return (...args) => {
@@ -220,24 +256,16 @@ function getEditsForFileRename(context, getEditsForFileRename$1) {
220
256
  if (data.components && fileName.endsWith("components.d.ts")) {
221
257
  const sourceFile = program.getSourceFile(fileName);
222
258
  if (!sourceFile) continue;
223
- const nodes = [];
224
- if (fileName.endsWith("types/components.d.ts")) {
225
- for (const node of require_src.forEachNode(ts, sourceFile)) if (ts.isPropertySignature(node)) nodes.push(node);
226
- } else for (const node of require_src.forEachNode(ts, sourceFile)) if (ts.isVariableDeclaration(node)) nodes.push(node);
227
- for (const node of nodes) {
228
- const start = node.getStart(sourceFile);
229
- const end = node.getEnd();
230
- if (textChanges.every(({ span }) => span.start < start || span.start + span.length > end)) continue;
231
- const symbols = info.languageService.findReferences(fileName, start);
259
+ for (const { span } of textChanges) for (const node of forEachTouchNode(ts, sourceFile, span.start)) {
260
+ if (!ts.isPropertySignature(node) && !ts.isVariableDeclaration(node)) continue;
261
+ const position = node.name.getStart(sourceFile);
262
+ const res = info.languageService.getReferencesAtPosition(fileName, position)?.filter((entry) => !entry.fileName.startsWith(data.buildDir));
232
263
  const lazy = node.type && ts.isTypeReferenceNode(node.type) && ts.isIdentifier(node.type.typeName) && node.type.typeName.text === "LazyComponent";
233
- for (const reference of symbols?.flatMap(({ references: references$1 }) => references$1) ?? []) {
234
- if (reference.isDefinition) continue;
235
- const { fileName: fileName$1, textSpan } = reference;
236
- (references[fileName$1] ??= []).push({
237
- textSpan: toSourceSpan(context.language, fileName$1, textSpan) ?? textSpan,
238
- lazy: lazy || void 0
239
- });
240
- }
264
+ for (const { fileName: fileName$1, textSpan } of res ?? []) (references[fileName$1] ??= []).push({
265
+ textSpan: toSourceSpan(context.language, fileName$1, textSpan) ?? textSpan,
266
+ lazy: lazy || void 0
267
+ });
268
+ break;
241
269
  }
242
270
  }
243
271
  if (!fileName.startsWith(data.buildDir)) changes.push(change);
@@ -249,18 +277,44 @@ function getEditsForFileRename(context, getEditsForFileRename$1) {
249
277
  return changes;
250
278
  };
251
279
  }
252
- function toSourceSpan(language, fileName, textSpan) {
253
- const sourceScript = language?.scripts.get(fileName);
254
- if (!sourceScript?.generated) return;
255
- const serviceScript = sourceScript.generated.languagePlugin.typescript?.getServiceScript(sourceScript.generated.root);
256
- if (!serviceScript) return;
257
- const map = language.maps.get(serviceScript.code, sourceScript);
258
- const leadingOffset = sourceScript.snapshot.getLength();
259
- for (const [start, end] of map.toSourceRange(textSpan.start - leadingOffset, textSpan.start + textSpan.length - leadingOffset, false)) return {
260
- start,
261
- length: end - start
262
- };
263
- }
280
+
281
+ //#endregion
282
+ //#region src/typescript/index.ts
283
+ const plugin = (module$1) => {
284
+ const { typescript: ts } = module$1;
285
+ return { create(info) {
286
+ const currentDirectory = info.languageServiceHost.getCurrentDirectory();
287
+ const path = (0, pathe.join)(currentDirectory, "dxup/data.json");
288
+ const data = {
289
+ buildDir: currentDirectory,
290
+ configFiles: [],
291
+ components: true,
292
+ nitroRoutes: true,
293
+ runtimeConfig: true,
294
+ ...JSON.parse(ts.sys.readFile(path) ?? "{}")
295
+ };
296
+ const server = createEventServer(info);
297
+ const context = {
298
+ ts,
299
+ info,
300
+ data,
301
+ server
302
+ };
303
+ setTimeout(() => {
304
+ context.language = (info.project.__vue__ ?? info.project["program"]?.__vue__)?.language;
305
+ }, 500);
306
+ for (const [key, method] of [
307
+ ["findRenameLocations", findRenameLocations.bind(null, context)],
308
+ ["getDefinitionAndBoundSpan", getDefinitionAndBoundSpan.bind(null, context)],
309
+ ["getEditsForFileRename", getEditsForFileRename.bind(null, context)]
310
+ ]) {
311
+ const original = info.languageService[key];
312
+ info.languageService[key] = method(original);
313
+ }
314
+ return info.languageService;
315
+ } };
316
+ };
317
+ var typescript_default = plugin;
264
318
 
265
319
  //#endregion
266
320
  module.exports = typescript_default;
package/package.json CHANGED
@@ -1,14 +1,13 @@
1
1
  {
2
2
  "name": "@dxup/nuxt",
3
3
  "type": "module",
4
- "version": "0.0.4",
5
- "description": "TypeScript and Vue plugins for Nuxt",
4
+ "version": "0.0.5",
5
+ "description": "TypeScript plugins for Nuxt",
6
6
  "author": "KazariEX",
7
7
  "license": "MIT",
8
8
  "repository": "KazariEX/dxup",
9
9
  "exports": {
10
10
  ".": "./dist/module.js",
11
- "./vue/nitro-routes": "./dist/vue/nitro-routes.cjs",
12
11
  "./package.json": "./package.json"
13
12
  },
14
13
  "main": "./dist/typescript.cjs",
@@ -1,31 +0,0 @@
1
-
2
- //#region ../shared/src/index.ts
3
- function* forEachNode(ts, node) {
4
- yield node;
5
- const children = [];
6
- ts.forEachChild(node, (child) => {
7
- children.push(child);
8
- });
9
- for (const child of children) yield* forEachNode(ts, child);
10
- }
11
- function walkNodes(ts, node, callback) {
12
- callback(node, () => {
13
- ts.forEachChild(node, (child) => {
14
- walkNodes(ts, child, callback);
15
- });
16
- });
17
- }
18
-
19
- //#endregion
20
- Object.defineProperty(exports, 'forEachNode', {
21
- enumerable: true,
22
- get: function () {
23
- return forEachNode;
24
- }
25
- });
26
- Object.defineProperty(exports, 'walkNodes', {
27
- enumerable: true,
28
- get: function () {
29
- return walkNodes;
30
- }
31
- });
@@ -1,33 +0,0 @@
1
- const require_src = require('../src-BfXMgjZD.cjs');
2
-
3
- //#region src/vue/nitro-routes.ts
4
- const functionNames = new Set([
5
- "$fetch",
6
- "useFetch",
7
- "useLazyFetch"
8
- ]);
9
- const plugin = ({ modules: { typescript: ts } }) => {
10
- return {
11
- version: 2.2,
12
- resolveEmbeddedCode(fileName, sfc, embeddedFile) {
13
- if (!embeddedFile.id.startsWith("script_")) return;
14
- const { scriptSetup } = sfc;
15
- if (!scriptSetup) return;
16
- const codes = [];
17
- for (const node of require_src.forEachNode(ts, scriptSetup.ast)) if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && functionNames.has(node.expression.text) && node.arguments.length && ts.isStringLiteralLike(node.arguments[0])) {
18
- const arg = node.arguments[0];
19
- codes.push(`/** @type {__VLS_InternalApi[`, [
20
- arg.getText(scriptSetup.ast),
21
- sfc.scriptSetup.name,
22
- arg.getStart(scriptSetup.ast),
23
- { navigation: true }
24
- ], `]} */;\n`);
25
- }
26
- if (codes.length) embeddedFile.content.push(`import type { InternalApi as __VLS_InternalApi } from 'nitropack/types';\n`, ...codes);
27
- }
28
- };
29
- };
30
- var nitro_routes_default = plugin;
31
-
32
- //#endregion
33
- module.exports = nitro_routes_default;
@@ -1,5 +0,0 @@
1
- import { VueLanguagePlugin } from "@vue/language-core";
2
-
3
- //#region src/vue/nitro-routes.d.ts
4
- declare const plugin: VueLanguagePlugin;
5
- export = plugin;