@dxup/nuxt 0.1.0 → 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/README.md +1 -0
- package/dist/module.d.ts +27 -4
- package/dist/module.js +14 -11
- package/dist/typescript.cjs +122 -55
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@ This is a TypeScript plugin that improves Nuxt DX.
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
11
|
- Update references when renaming auto imported component files
|
|
12
|
+
- Go to definition for dynamic imports with glob patterns
|
|
12
13
|
- Go to definition for nitro routes in data fetching methods
|
|
13
14
|
- Go to definition for runtime config
|
|
14
15
|
- [@dxup/unimport](/packages/unimport)
|
package/dist/module.d.ts
CHANGED
|
@@ -2,10 +2,33 @@ import * as _nuxt_schema0 from "@nuxt/schema";
|
|
|
2
2
|
|
|
3
3
|
//#region src/module/index.d.ts
|
|
4
4
|
interface ModuleOptions {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
features?: {
|
|
6
|
+
/**
|
|
7
|
+
* Whether to update references when renaming auto imported component files.
|
|
8
|
+
* @default true
|
|
9
|
+
*/
|
|
10
|
+
components?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Whether to enable Go to Definition for dynamic imports with glob patterns.
|
|
13
|
+
* @default true
|
|
14
|
+
*/
|
|
15
|
+
importGlob?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Whether to enable Go to Definition for nitro routes in data fetching methods.
|
|
18
|
+
* @default true
|
|
19
|
+
*/
|
|
20
|
+
nitroRoutes?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Whether to enable Go to Definition for runtime config.
|
|
23
|
+
* @default true
|
|
24
|
+
*/
|
|
25
|
+
runtimeConfig?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Whether to enable enhanced navigation for auto imported APIs.
|
|
28
|
+
* @default true
|
|
29
|
+
*/
|
|
30
|
+
unimport?: boolean;
|
|
31
|
+
};
|
|
9
32
|
}
|
|
10
33
|
declare const _default: _nuxt_schema0.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
|
11
34
|
//#endregion
|
package/dist/module.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { addTemplate, defineNuxtModule } from "@nuxt/kit";
|
|
1
|
+
import { addTemplate, defineNuxtModule, useNitro } from "@nuxt/kit";
|
|
2
2
|
import { Buffer } from "node:buffer";
|
|
3
3
|
import EventEmitter from "node:events";
|
|
4
4
|
import { mkdir, open, readFile, writeFile } from "node:fs/promises";
|
|
@@ -69,15 +69,16 @@ var module_default = defineNuxtModule({
|
|
|
69
69
|
name,
|
|
70
70
|
configKey: "dxup"
|
|
71
71
|
},
|
|
72
|
-
defaults: {
|
|
72
|
+
defaults: { features: {
|
|
73
73
|
components: true,
|
|
74
|
+
importGlob: true,
|
|
74
75
|
nitroRoutes: true,
|
|
75
76
|
runtimeConfig: true,
|
|
76
77
|
unimport: true
|
|
77
|
-
},
|
|
78
|
+
} },
|
|
78
79
|
async setup(options, nuxt) {
|
|
79
80
|
const pluginsTs = [{ name: "@dxup/nuxt" }];
|
|
80
|
-
if (options.unimport) pluginsTs.unshift({ name: "@dxup/unimport" });
|
|
81
|
+
if (options.features?.unimport) pluginsTs.unshift({ name: "@dxup/unimport" });
|
|
81
82
|
append(pluginsTs, nuxt.options, "typescript", "tsConfig", "compilerOptions");
|
|
82
83
|
append(pluginsTs, nuxt.options.nitro, "typescript", "tsConfig", "compilerOptions");
|
|
83
84
|
append(pluginsTs, nuxt.options, "typescript", "sharedTsConfig", "compilerOptions");
|
|
@@ -85,14 +86,16 @@ var module_default = defineNuxtModule({
|
|
|
85
86
|
addTemplate({
|
|
86
87
|
filename: "dxup/data.json",
|
|
87
88
|
write: true,
|
|
88
|
-
getContents() {
|
|
89
|
+
getContents({ nuxt: nuxt$1 }) {
|
|
90
|
+
const nitro = useNitro();
|
|
91
|
+
const nitroRoutes = options.features?.nitroRoutes && Object.fromEntries(nitro.scannedHandlers.filter((item) => item.route).map((item) => [`${item.route}+${item.method ?? "get"}`, item.handler]));
|
|
89
92
|
const data = {
|
|
90
|
-
buildDir: nuxt.options.buildDir,
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
nitroRoutes
|
|
95
|
-
runtimeConfig: options.runtimeConfig
|
|
93
|
+
buildDir: nuxt$1.options.buildDir,
|
|
94
|
+
configFiles: [...nuxt$1.options._nuxtConfigFiles, ...nuxt$1.options._layers.map((layer) => layer._configFile).filter(Boolean)],
|
|
95
|
+
components: options.features?.components,
|
|
96
|
+
importGlob: options.features?.importGlob,
|
|
97
|
+
nitroRoutes,
|
|
98
|
+
runtimeConfig: options.features?.runtimeConfig
|
|
96
99
|
};
|
|
97
100
|
return JSON.stringify(data, null, 2);
|
|
98
101
|
}
|
package/dist/typescript.cjs
CHANGED
|
@@ -25,6 +25,8 @@ let pathe = require("pathe");
|
|
|
25
25
|
pathe = __toESM(pathe);
|
|
26
26
|
let node_fs_promises = require("node:fs/promises");
|
|
27
27
|
node_fs_promises = __toESM(node_fs_promises);
|
|
28
|
+
let tinyglobby = require("tinyglobby");
|
|
29
|
+
tinyglobby = __toESM(tinyglobby);
|
|
28
30
|
|
|
29
31
|
//#region src/event/server.ts
|
|
30
32
|
function createEventServer(info) {
|
|
@@ -63,10 +65,8 @@ function* binaryVisit(ts, sourceFile, node, position) {
|
|
|
63
65
|
while (left <= right) {
|
|
64
66
|
const mid = Math.floor((left + right) / 2);
|
|
65
67
|
const node$1 = nodes[mid];
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (position < start) right = mid - 1;
|
|
69
|
-
else if (position > end) left = mid + 1;
|
|
68
|
+
if (position > node$1.getEnd()) left = mid + 1;
|
|
69
|
+
else if (position < node$1.getStart(sourceFile)) right = mid - 1;
|
|
70
70
|
else {
|
|
71
71
|
yield node$1;
|
|
72
72
|
yield* binaryVisit(ts, sourceFile, node$1, position);
|
|
@@ -74,6 +74,9 @@ function* binaryVisit(ts, sourceFile, node, position) {
|
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
|
+
function isTextSpanEqual(node, textSpan, sourceFile) {
|
|
78
|
+
return textSpan.start + textSpan.length === node.getEnd() && textSpan.start === node.getStart(sourceFile);
|
|
79
|
+
}
|
|
77
80
|
|
|
78
81
|
//#endregion
|
|
79
82
|
//#region src/typescript/features/getDefinitionAndBoundSpan.ts
|
|
@@ -82,49 +85,21 @@ const fetchFunctions = new Set([
|
|
|
82
85
|
"useFetch",
|
|
83
86
|
"useLazyFetch"
|
|
84
87
|
]);
|
|
85
|
-
const nonApiRE = /^(?!\/api\/)/;
|
|
86
88
|
function getDefinitionAndBoundSpan(context, getDefinitionAndBoundSpan$1) {
|
|
87
89
|
const { ts, info, data } = context;
|
|
88
90
|
return (...args) => {
|
|
89
91
|
const result = getDefinitionAndBoundSpan$1(...args);
|
|
90
|
-
if (!result
|
|
92
|
+
if (!result) {
|
|
91
93
|
const program$1 = info.languageService.getProgram();
|
|
92
94
|
const sourceFile = program$1.getSourceFile(args[0]);
|
|
93
95
|
if (!sourceFile) return;
|
|
94
96
|
const checker = program$1.getTypeChecker();
|
|
97
|
+
let res;
|
|
95
98
|
for (const node of forEachTouchingNode(ts, sourceFile, args[1])) {
|
|
96
|
-
if (
|
|
97
|
-
|
|
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, methodType] = (node.expression.text === "$fetch" ? typeArguments?.[2] && checker.getTypeArguments(typeArguments?.[2]) : typeArguments?.slice(2)) ?? [];
|
|
105
|
-
if (!routeType?.isStringLiteral() || !methodType?.isStringLiteral()) break;
|
|
106
|
-
const route = routeType.value.replace(nonApiRE, "/routes");
|
|
107
|
-
const method = methodType.value;
|
|
108
|
-
const path = (0, pathe.join)(data.serverDir, `${route}.${method}.ts`);
|
|
109
|
-
return {
|
|
110
|
-
textSpan: {
|
|
111
|
-
start,
|
|
112
|
-
length: end - start
|
|
113
|
-
},
|
|
114
|
-
definitions: [{
|
|
115
|
-
fileName: path,
|
|
116
|
-
textSpan: {
|
|
117
|
-
start: 0,
|
|
118
|
-
length: 0
|
|
119
|
-
},
|
|
120
|
-
kind: ts.ScriptElementKind.scriptElement,
|
|
121
|
-
name: path,
|
|
122
|
-
containerKind: ts.ScriptElementKind.unknown,
|
|
123
|
-
containerName: ""
|
|
124
|
-
}]
|
|
125
|
-
};
|
|
99
|
+
if (data.importGlob) res ??= visitImportGlob(ts, info, sourceFile, node, args[1]);
|
|
100
|
+
if (data.nitroRoutes) res ??= visitNitroRoutes(ts, checker, sourceFile, node, args[1], data.nitroRoutes);
|
|
126
101
|
}
|
|
127
|
-
return;
|
|
102
|
+
if (res) return res;
|
|
128
103
|
}
|
|
129
104
|
if (!result?.definitions?.length) return result;
|
|
130
105
|
const program = info.languageService.getProgram();
|
|
@@ -145,6 +120,88 @@ function getDefinitionAndBoundSpan(context, getDefinitionAndBoundSpan$1) {
|
|
|
145
120
|
};
|
|
146
121
|
};
|
|
147
122
|
}
|
|
123
|
+
function visitImportGlob(ts, info, sourceFile, node, position) {
|
|
124
|
+
if (!ts.isCallExpression(node) || !node.arguments.length) return;
|
|
125
|
+
const firstArg = node.arguments[0];
|
|
126
|
+
const start = firstArg.getStart(sourceFile);
|
|
127
|
+
const end = firstArg.getEnd();
|
|
128
|
+
if (position < start || position > end) return;
|
|
129
|
+
let pattern;
|
|
130
|
+
const callText = node.expression.getText(sourceFile);
|
|
131
|
+
if (callText === "import" && ts.isTemplateExpression(firstArg)) pattern = [firstArg.head.text, ...firstArg.templateSpans.map((span) => span.literal.text)].join("*");
|
|
132
|
+
else if (callText === "import.meta.glob" && ts.isStringLiteral(firstArg)) pattern = firstArg.text;
|
|
133
|
+
if (pattern === void 0) return;
|
|
134
|
+
const resolved = ts.resolveModuleName(pattern, sourceFile.fileName, info.languageServiceHost.getCompilationSettings(), {
|
|
135
|
+
fileExists: () => true,
|
|
136
|
+
readFile: () => ""
|
|
137
|
+
});
|
|
138
|
+
if (!resolved?.resolvedModule) return;
|
|
139
|
+
const extension = (0, pathe.extname)(pattern);
|
|
140
|
+
const arbitrary = `.d${extension}.ts`;
|
|
141
|
+
pattern = resolved.resolvedModule.resolvedFileName;
|
|
142
|
+
if (resolved.resolvedModule.extension === arbitrary) pattern = pattern.slice(0, -arbitrary.length) + extension;
|
|
143
|
+
const fileNames = (0, tinyglobby.globSync)(pattern, { absolute: true });
|
|
144
|
+
return {
|
|
145
|
+
textSpan: {
|
|
146
|
+
start,
|
|
147
|
+
length: end - start
|
|
148
|
+
},
|
|
149
|
+
definitions: fileNames.map((fileName) => ({
|
|
150
|
+
fileName,
|
|
151
|
+
textSpan: {
|
|
152
|
+
start: 0,
|
|
153
|
+
length: 0
|
|
154
|
+
},
|
|
155
|
+
kind: ts.ScriptElementKind.unknown,
|
|
156
|
+
name: fileName,
|
|
157
|
+
containerKind: ts.ScriptElementKind.unknown,
|
|
158
|
+
containerName: ""
|
|
159
|
+
}))
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function visitNitroRoutes(ts, checker, sourceFile, node, position, nitroRoutes) {
|
|
163
|
+
if (!ts.isCallExpression(node) || !ts.isIdentifier(node.expression) || !fetchFunctions.has(node.expression.text) || !node.arguments.length) return;
|
|
164
|
+
const firstArg = node.arguments[0];
|
|
165
|
+
const start = firstArg.getStart(sourceFile);
|
|
166
|
+
const end = firstArg.getEnd();
|
|
167
|
+
if (position < start || position > end) return;
|
|
168
|
+
const resolvedSignature = checker.getResolvedSignature(node);
|
|
169
|
+
if (!resolvedSignature) return;
|
|
170
|
+
const typeArguments = checker.getTypeArgumentsForResolvedSignature(resolvedSignature);
|
|
171
|
+
let routeType;
|
|
172
|
+
let methodType;
|
|
173
|
+
if (node.expression.text === "$fetch") {
|
|
174
|
+
routeType = typeArguments?.[1];
|
|
175
|
+
const symbol = typeArguments?.[2].getProperty("method");
|
|
176
|
+
methodType = symbol ? checker.getTypeOfSymbol(symbol) : void 0;
|
|
177
|
+
} else {
|
|
178
|
+
routeType = typeArguments?.[2];
|
|
179
|
+
methodType = typeArguments?.[3];
|
|
180
|
+
}
|
|
181
|
+
if (!routeType?.isStringLiteral()) return;
|
|
182
|
+
const paths = [];
|
|
183
|
+
for (const type of methodType?.isUnion() ? methodType.types : [methodType]) if (type?.isStringLiteral()) {
|
|
184
|
+
const path = nitroRoutes[`${routeType.value}+${type.value}`];
|
|
185
|
+
if (path !== void 0) paths.push(path);
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
textSpan: {
|
|
189
|
+
start,
|
|
190
|
+
length: end - start
|
|
191
|
+
},
|
|
192
|
+
definitions: paths.map((path) => ({
|
|
193
|
+
fileName: path,
|
|
194
|
+
textSpan: {
|
|
195
|
+
start: 0,
|
|
196
|
+
length: 0
|
|
197
|
+
},
|
|
198
|
+
kind: ts.ScriptElementKind.scriptElement,
|
|
199
|
+
name: path,
|
|
200
|
+
containerKind: ts.ScriptElementKind.unknown,
|
|
201
|
+
containerName: ""
|
|
202
|
+
}))
|
|
203
|
+
};
|
|
204
|
+
}
|
|
148
205
|
function visitRuntimeConfig(context, sourceFile, definition) {
|
|
149
206
|
const { ts } = context;
|
|
150
207
|
let definitions = [];
|
|
@@ -154,10 +211,7 @@ function visitRuntimeConfig(context, sourceFile, definition) {
|
|
|
154
211
|
if (ts.isInterfaceDeclaration(node) && ts.isIdentifier(node.name)) key = node.name.text;
|
|
155
212
|
else if (ts.isPropertySignature(node) && ts.isIdentifier(node.name)) {
|
|
156
213
|
key = node.name.text;
|
|
157
|
-
|
|
158
|
-
const start = node.name.getStart(sourceFile);
|
|
159
|
-
const end = node.name.getEnd();
|
|
160
|
-
if (start === textSpan.start && end - start === textSpan.length) {
|
|
214
|
+
if (isTextSpanEqual(node.name, definition.textSpan, sourceFile)) {
|
|
161
215
|
path.push(key);
|
|
162
216
|
definitions = [...forwardRuntimeConfig(context, definition, path)];
|
|
163
217
|
break;
|
|
@@ -280,36 +334,49 @@ function getEditsForFileRename(context, getEditsForFileRename$1) {
|
|
|
280
334
|
const plugin = (module$1) => {
|
|
281
335
|
const { typescript: ts } = module$1;
|
|
282
336
|
return { create(info) {
|
|
283
|
-
const currentDirectory = info.languageServiceHost.getCurrentDirectory();
|
|
284
|
-
const path = (0, pathe.join)(currentDirectory, "dxup/data.json");
|
|
285
337
|
const context = {
|
|
286
338
|
ts,
|
|
287
339
|
info,
|
|
288
|
-
data:
|
|
289
|
-
buildDir: currentDirectory,
|
|
290
|
-
configFiles: [],
|
|
291
|
-
components: true,
|
|
292
|
-
nitroRoutes: true,
|
|
293
|
-
runtimeConfig: true,
|
|
294
|
-
...JSON.parse(ts.sys.readFile(path) ?? "{}")
|
|
295
|
-
},
|
|
340
|
+
data: createData(ts, info),
|
|
296
341
|
server: createEventServer(info)
|
|
297
342
|
};
|
|
298
343
|
setTimeout(() => {
|
|
299
344
|
context.language = (info.project.__vue__ ?? info.project["program"]?.__vue__)?.language;
|
|
300
345
|
}, 500);
|
|
301
346
|
for (const [key, method] of [
|
|
302
|
-
["findRenameLocations", findRenameLocations
|
|
303
|
-
["getDefinitionAndBoundSpan", getDefinitionAndBoundSpan
|
|
304
|
-
["getEditsForFileRename", getEditsForFileRename
|
|
347
|
+
["findRenameLocations", findRenameLocations],
|
|
348
|
+
["getDefinitionAndBoundSpan", getDefinitionAndBoundSpan],
|
|
349
|
+
["getEditsForFileRename", getEditsForFileRename]
|
|
305
350
|
]) {
|
|
306
351
|
const original = info.languageService[key];
|
|
307
|
-
info.languageService[key] = method(original);
|
|
352
|
+
info.languageService[key] = method(context, original);
|
|
308
353
|
}
|
|
309
354
|
return info.languageService;
|
|
310
355
|
} };
|
|
311
356
|
};
|
|
312
357
|
var typescript_default = plugin;
|
|
358
|
+
function createData(ts, info) {
|
|
359
|
+
const initialValue = {
|
|
360
|
+
buildDir: "",
|
|
361
|
+
configFiles: [],
|
|
362
|
+
components: true,
|
|
363
|
+
importGlob: true,
|
|
364
|
+
nitroRoutes: {},
|
|
365
|
+
runtimeConfig: true
|
|
366
|
+
};
|
|
367
|
+
const path = (0, pathe.join)(info.languageServiceHost.getCurrentDirectory(), "dxup/data.json");
|
|
368
|
+
const data = {};
|
|
369
|
+
update();
|
|
370
|
+
ts.sys.watchFile?.(path, update);
|
|
371
|
+
return data;
|
|
372
|
+
function update() {
|
|
373
|
+
const text = ts.sys.readFile(path);
|
|
374
|
+
Object.assign(data, {
|
|
375
|
+
...initialValue,
|
|
376
|
+
...text ? JSON.parse(text) : {}
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
}
|
|
313
380
|
|
|
314
381
|
//#endregion
|
|
315
382
|
module.exports = typescript_default;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxup/nuxt",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.0",
|
|
5
5
|
"description": "TypeScript plugin for Nuxt",
|
|
6
6
|
"author": "KazariEX",
|
|
7
7
|
"license": "MIT",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"@nuxt/kit": "^4.1.3",
|
|
20
20
|
"chokidar": "^4.0.3",
|
|
21
21
|
"pathe": "2.0.3",
|
|
22
|
+
"tinyglobby": "^0.2.15",
|
|
22
23
|
"@dxup/unimport": "^0.1.0"
|
|
23
24
|
},
|
|
24
25
|
"devDependencies": {
|