@dxup/nuxt 0.0.3 → 0.0.4

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
@@ -8,6 +8,7 @@ This is a collection of TypeScript and Vue plugins that improves Nuxt DX.
8
8
 
9
9
  ## Features
10
10
 
11
+ - Update references when renaming auto imported component files
11
12
  - Go to definition for nitro routes in data fetching methods within Vue files
12
13
  - Go to definition for runtime config
13
14
  - [@dxup/unimport](/packages/unimport)
package/dist/module.d.ts CHANGED
@@ -2,6 +2,7 @@ import * as _nuxt_schema0 from "@nuxt/schema";
2
2
 
3
3
  //#region src/module/index.d.ts
4
4
  interface ModuleOptions {
5
+ components?: boolean;
5
6
  nitroRoutes?: boolean;
6
7
  runtimeConfig?: boolean;
7
8
  unimport?: boolean;
package/dist/module.js CHANGED
@@ -1,8 +1,67 @@
1
1
  import { addTemplate, defineNuxtModule } from "@nuxt/kit";
2
+ import { Buffer } from "node:buffer";
3
+ import EventEmitter from "node:events";
4
+ import { mkdir, open, readFile, writeFile } from "node:fs/promises";
5
+ import { watch } from "chokidar";
6
+ import { dirname, join } from "pathe";
2
7
 
3
8
  //#region package.json
4
9
  var name = "@dxup/nuxt";
5
10
 
11
+ //#endregion
12
+ //#region src/event/client.ts
13
+ const responseRE = /^```json \{(?<key>.*)\}\n(?<value>[\s\S]*?)\n```$/;
14
+ async function createEventClient(nuxt) {
15
+ const path = join(nuxt.options.buildDir, "dxup/events.md");
16
+ await mkdir(dirname(path), { recursive: true });
17
+ await writeFile(path, "");
18
+ const fd = await open(path, "r");
19
+ const watcher = watch(path, { ignoreInitial: true });
20
+ nuxt.hook("close", async () => {
21
+ await fd.close();
22
+ await watcher.close();
23
+ });
24
+ const client = new EventEmitter();
25
+ let offset = 0;
26
+ watcher.on("change", async (path$1, stats) => {
27
+ if (!stats || stats.size <= offset) return;
28
+ const pos = offset;
29
+ offset = stats.size;
30
+ const buffer = Buffer.alloc(offset - pos);
31
+ await fd.read(buffer, 0, buffer.length, pos);
32
+ const match = buffer.toString("utf-8").trim().match(responseRE);
33
+ if (match) {
34
+ const { key, value } = match.groups;
35
+ client.emit(key, JSON.parse(value));
36
+ }
37
+ });
38
+ return client;
39
+ }
40
+
41
+ //#endregion
42
+ //#region src/module/events.ts
43
+ const uppercaseRE = /[A-Z]/;
44
+ async function onComponentsRename(nuxt, { fileName, references }) {
45
+ const component = Object.values(nuxt.apps).flatMap((app) => app.components).find((c) => c.filePath === fileName);
46
+ if (!component) return;
47
+ const tasks = Object.entries(references).map(async ([fileName$1, references$1]) => {
48
+ const code = await readFile(fileName$1, "utf-8");
49
+ const chunks = [];
50
+ let offset = 0;
51
+ for (const { textSpan, lazy } of references$1) {
52
+ const start = textSpan.start;
53
+ const end = start + textSpan.length;
54
+ const oldName = code.slice(start, end);
55
+ const newName = uppercaseRE.test(oldName) ? lazy ? "Lazy" + component.pascalName : component.pascalName : lazy ? "lazy-" + component.kebabName : component.kebabName;
56
+ chunks.push(code.slice(offset, start), newName);
57
+ offset = end;
58
+ }
59
+ chunks.push(code.slice(offset));
60
+ await writeFile(fileName$1, chunks.join(""));
61
+ });
62
+ await Promise.all(tasks);
63
+ }
64
+
6
65
  //#endregion
7
66
  //#region src/module/index.ts
8
67
  var module_default = defineNuxtModule({
@@ -11,6 +70,7 @@ var module_default = defineNuxtModule({
11
70
  configKey: "dxup"
12
71
  },
13
72
  defaults: {
73
+ components: true,
14
74
  nitroRoutes: true,
15
75
  runtimeConfig: true,
16
76
  unimport: true
@@ -19,24 +79,27 @@ var module_default = defineNuxtModule({
19
79
  const pluginsTs = [{ name: "@dxup/nuxt" }];
20
80
  const pluginsVue = [];
21
81
  if (options.nitroRoutes) pluginsVue.push("@dxup/nuxt/vue/nitro-routes");
22
- if (options.unimport) pluginsTs.push({ name: "@dxup/unimport" });
82
+ if (options.unimport) pluginsTs.unshift({ name: "@dxup/unimport" });
23
83
  append(pluginsTs, nuxt.options, "typescript", "tsConfig", "compilerOptions");
24
84
  append(pluginsTs, nuxt.options.nitro, "typescript", "tsConfig", "compilerOptions");
25
85
  append(pluginsTs, nuxt.options, "typescript", "sharedTsConfig", "compilerOptions");
26
86
  append(pluginsTs, nuxt.options, "typescript", "nodeTsConfig", "compilerOptions");
27
87
  append(pluginsVue, nuxt.options, "typescript", "tsConfig", "vueCompilerOptions");
28
88
  addTemplate({
29
- filename: "dxup.json",
89
+ filename: "dxup/data.json",
30
90
  write: true,
31
91
  getContents() {
32
92
  const data = {
93
+ buildDir: nuxt.options.buildDir,
94
+ configFiles: [...nuxt.options._nuxtConfigFiles, ...nuxt.options._layers.map((layer) => layer._configFile).filter(Boolean)],
95
+ components: options.components,
33
96
  nitroRoutes: options.nitroRoutes,
34
- runtimeConfig: options.runtimeConfig,
35
- configFiles: [...nuxt.options._nuxtConfigFiles, ...nuxt.options._layers.map((layer) => layer._configFile).filter(Boolean)]
97
+ runtimeConfig: options.runtimeConfig
36
98
  };
37
99
  return JSON.stringify(data, null, 2);
38
100
  }
39
101
  });
102
+ (await createEventClient(nuxt)).on("components:rename", (data) => onComponentsRename(nuxt, data));
40
103
  }
41
104
  });
42
105
  function append(plugins, target, ...keys) {
@@ -1,17 +1,17 @@
1
1
 
2
- //#region src/utils/ast.ts
3
- function* forEachNode(node) {
2
+ //#region ../shared/src/index.ts
3
+ function* forEachNode(ts, node) {
4
4
  yield node;
5
5
  const children = [];
6
- node.forEachChild((child) => {
6
+ ts.forEachChild(node, (child) => {
7
7
  children.push(child);
8
8
  });
9
- for (const child of children) yield* forEachNode(child);
9
+ for (const child of children) yield* forEachNode(ts, child);
10
10
  }
11
- function walkNodes(node, callback) {
11
+ function walkNodes(ts, node, callback) {
12
12
  callback(node, () => {
13
- node.forEachChild((child) => {
14
- walkNodes(child, callback);
13
+ ts.forEachChild(node, (child) => {
14
+ walkNodes(ts, child, callback);
15
15
  });
16
16
  });
17
17
  }
@@ -21,27 +21,51 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
21
21
  }) : target, mod));
22
22
 
23
23
  //#endregion
24
- const require_ast = require('./ast-DJW3KREB.cjs');
25
- let node_path = require("node:path");
26
- node_path = __toESM(node_path);
24
+ const require_src = require('./src-BfXMgjZD.cjs');
25
+ let pathe = require("pathe");
26
+ pathe = __toESM(pathe);
27
+ let node_fs_promises = require("node:fs/promises");
28
+ node_fs_promises = __toESM(node_fs_promises);
27
29
 
30
+ //#region src/event/server.ts
31
+ function createEventServer(info) {
32
+ 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();
35
+ }
36
+ return { write };
37
+ }
38
+
39
+ //#endregion
28
40
  //#region src/typescript/index.ts
29
41
  const plugin = (module$1) => {
30
42
  const { typescript: ts } = module$1;
31
43
  return { create(info) {
32
- const path = (0, node_path.join)(info.languageServiceHost.getCurrentDirectory(), "dxup.json");
44
+ const currentDirectory = info.languageServiceHost.getCurrentDirectory();
45
+ const path = (0, pathe.join)(currentDirectory, "dxup/data.json");
33
46
  const data = {
47
+ buildDir: currentDirectory,
48
+ configFiles: [],
49
+ components: true,
34
50
  nitroRoutes: true,
35
51
  runtimeConfig: true,
36
- configFiles: [],
37
52
  ...JSON.parse(ts.sys.readFile(path) ?? "{}")
38
53
  };
54
+ const server = createEventServer(info);
39
55
  const context = {
40
56
  ts,
41
57
  info,
42
- data
58
+ data,
59
+ server
43
60
  };
44
- for (const [key, method] of [["getDefinitionAndBoundSpan", getDefinitionAndBoundSpan.bind(null, context)]]) {
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
+ ]) {
45
69
  const original = info.languageService[key];
46
70
  info.languageService[key] = method(original);
47
71
  }
@@ -49,10 +73,18 @@ const plugin = (module$1) => {
49
73
  } };
50
74
  };
51
75
  var typescript_default = plugin;
76
+ function findRenameLocations(context, findRenameLocations$1) {
77
+ const { data } = context;
78
+ return (...args) => {
79
+ return findRenameLocations$1(...args)?.filter((edit) => {
80
+ return !edit.fileName.startsWith(data.buildDir);
81
+ });
82
+ };
83
+ }
52
84
  function getDefinitionAndBoundSpan(context, getDefinitionAndBoundSpan$1) {
53
85
  const { info, data } = context;
54
- return (fileName, position) => {
55
- const result = getDefinitionAndBoundSpan$1(fileName, position);
86
+ return (...args) => {
87
+ const result = getDefinitionAndBoundSpan$1(...args);
56
88
  if (!result?.definitions?.length) return result;
57
89
  const program = info.languageService.getProgram();
58
90
  const definitions = new Set(result.definitions);
@@ -78,7 +110,7 @@ function getDefinitionAndBoundSpan(context, getDefinitionAndBoundSpan$1) {
78
110
  function visitNitroRoutes(context, sourceFile, definition, getDefinitionAndBoundSpan$1) {
79
111
  const { ts } = context;
80
112
  const definitions = [];
81
- for (const node of require_ast.forEachNode(sourceFile)) {
113
+ for (const node of require_src.forEachNode(ts, sourceFile)) {
82
114
  if (!ts.isPropertySignature(node) || !node.type || !ts.isTypeLiteralNode(node.type)) continue;
83
115
  const { textSpan } = definition;
84
116
  const start = node.name.getStart(sourceFile);
@@ -100,7 +132,7 @@ function visitRuntimeConfig(context, sourceFile, definition) {
100
132
  const { ts } = context;
101
133
  let definitions = [];
102
134
  const path = [];
103
- require_ast.walkNodes(sourceFile, (node, next) => {
135
+ require_src.walkNodes(ts, sourceFile, (node, next) => {
104
136
  let key;
105
137
  if (ts.isInterfaceDeclaration(node) && ts.isIdentifier(node.name)) key = node.name.text;
106
138
  else if (ts.isPropertySignature(node) && ts.isIdentifier(node.name)) {
@@ -175,6 +207,60 @@ function* proxyRuntimeConfig(context, definition, path) {
175
207
  }
176
208
  }
177
209
  }
210
+ function getEditsForFileRename(context, getEditsForFileRename$1) {
211
+ const { ts, info, data, server } = context;
212
+ return (...args) => {
213
+ const result = getEditsForFileRename$1(...args);
214
+ if (!result?.length) return result;
215
+ const program = info.languageService.getProgram();
216
+ const changes = [];
217
+ const references = {};
218
+ for (const change of result) {
219
+ const { fileName, textChanges } = change;
220
+ if (data.components && fileName.endsWith("components.d.ts")) {
221
+ const sourceFile = program.getSourceFile(fileName);
222
+ 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);
232
+ 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
+ }
241
+ }
242
+ }
243
+ if (!fileName.startsWith(data.buildDir)) changes.push(change);
244
+ }
245
+ if (Object.keys(references).length) server.write("components:rename", {
246
+ fileName: args[1],
247
+ references
248
+ });
249
+ return changes;
250
+ };
251
+ }
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
+ }
178
264
 
179
265
  //#endregion
180
266
  module.exports = typescript_default;
@@ -1,4 +1,4 @@
1
- const require_ast = require('../ast-DJW3KREB.cjs');
1
+ const require_src = require('../src-BfXMgjZD.cjs');
2
2
 
3
3
  //#region src/vue/nitro-routes.ts
4
4
  const functionNames = new Set([
@@ -14,7 +14,7 @@ const plugin = ({ modules: { typescript: ts } }) => {
14
14
  const { scriptSetup } = sfc;
15
15
  if (!scriptSetup) return;
16
16
  const codes = [];
17
- for (const node of require_ast.forEachNode(scriptSetup.ast)) if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && functionNames.has(node.expression.text) && node.arguments.length && ts.isStringLiteralLike(node.arguments[0])) {
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
18
  const arg = node.arguments[0];
19
19
  codes.push(`/** @type {__VLS_InternalApi[`, [
20
20
  arg.getText(scriptSetup.ast),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dxup/nuxt",
3
3
  "type": "module",
4
- "version": "0.0.3",
4
+ "version": "0.0.4",
5
5
  "description": "TypeScript and Vue plugins for Nuxt",
6
6
  "author": "KazariEX",
7
7
  "license": "MIT",
@@ -18,9 +18,14 @@
18
18
  ],
19
19
  "dependencies": {
20
20
  "@nuxt/kit": "^4.1.2",
21
+ "chokidar": "^4.0.3",
22
+ "pathe": "2.0.3",
21
23
  "@dxup/unimport": "^0.0.1"
22
24
  },
23
25
  "devDependencies": {
26
+ "@dxup/shared": "",
27
+ "@volar/language-core": "^2.4.23",
28
+ "@volar/typescript": "^2.4.23",
24
29
  "@vue/language-core": "^3.0.8",
25
30
  "nuxt": "^4.1.2",
26
31
  "typescript": "^5.9.2"
@@ -28,6 +33,6 @@
28
33
  "scripts": {
29
34
  "build": "tsdown",
30
35
  "dev": "tsdown -w --sourcemap",
31
- "release": "bumpp"
36
+ "release": "node ../../scripts/release.ts"
32
37
  }
33
38
  }