@dxup/nuxt 0.4.0 → 0.5.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
@@ -24,6 +24,12 @@ This is a TypeScript plugin that improves Nuxt DX.
24
24
  experimental: {
25
25
  typescriptPlugin: true,
26
26
  },
27
+ dxup: {
28
+ features: {
29
+ // Enable opt-in features
30
+ namedLayoutSlots: true,
31
+ },
32
+ },
27
33
  });
28
34
  ```
29
35
 
@@ -50,7 +56,40 @@ import.meta.glob("~/assets/*.webp");
50
56
  // ^^^^^^^^^^^^^^^^^
51
57
  ```
52
58
 
53
- ### 3. nitroRoutes
59
+ ### 3. namedLayoutSlots
60
+
61
+ **Default:** `false`
62
+
63
+ Write top-level named slots in your pages:
64
+
65
+ ```vue
66
+ <!-- layouts/center.vue -->
67
+ <template>
68
+ <slot></slot>
69
+ <slot name="side" one="one"></slot>
70
+ </template>
71
+ ```
72
+
73
+ ```vue
74
+ <!-- pages/about.vue -->
75
+ <script lang="ts" setup>
76
+ definePageMeta({
77
+ layout: "center",
78
+ });
79
+ </script>
80
+
81
+ <template>
82
+ <template #side="{ one }">
83
+ This "{{ one }}" comes from the layout slot.
84
+ <!-- ^^^ -->
85
+ </template>
86
+ <div>About Page</div>
87
+ </template>
88
+ ```
89
+
90
+ And them will be forwarded to the active layout automatically.
91
+
92
+ ### 4. nitroRoutes
54
93
 
55
94
  Go to definition for nitro routes in data fetching methods.
56
95
 
@@ -62,7 +101,7 @@ useFetch("/api/foo");
62
101
 
63
102
  It will fallback to resolve the URL from your `public` directory when no nitro routes match.
64
103
 
65
- ### 4. pageMeta
104
+ ### 5. pageMeta
66
105
 
67
106
  Go to definition for page metadata.
68
107
 
@@ -75,7 +114,7 @@ definePageMeta({
75
114
  });
76
115
  ```
77
116
 
78
- ### 5. runtimeConfig
117
+ ### 6. runtimeConfig
79
118
 
80
119
  Go to definition for runtime config.
81
120
 
@@ -86,7 +125,7 @@ Go to definition for runtime config.
86
125
  </template>
87
126
  ```
88
127
 
89
- ### 6. typedPages
128
+ ### 7. typedPages
90
129
 
91
130
  Go to definition for typed pages.
92
131
 
@@ -99,11 +138,11 @@ Go to definition for typed pages.
99
138
 
100
139
  It can be triggered on the `name` property of an object literal constrained by the `RouteLocationRaw` type.
101
140
 
102
- ### 7. unimport
141
+ ### 8. unimport
103
142
 
104
143
  Please refer to the [@dxup/unimport](/packages/unimport) package for more details.
105
144
 
106
- ### 8. unofficial
145
+ ### 9. unofficial
107
146
 
108
147
  Find references for SFC on `<template>`.
109
148
 
@@ -0,0 +1,4 @@
1
+ //#region src/module/named-layout-slots/components/forward.d.ts
2
+ declare const _default: import("vue").DefineSetupFnComponent<Record<string, any>, {}, {}, Record<string, any> & {}, import("vue").PublicProps>;
3
+ //#endregion
4
+ export { _default as default };
@@ -0,0 +1,10 @@
1
+ import { defineComponent } from "vue";
2
+ import { injectLayoutSlots } from "#build/dxup/layouts.mjs";
3
+ //#region src/module/named-layout-slots/components/forward.ts
4
+ var forward_default = defineComponent((props, ctx) => {
5
+ const slots = injectLayoutSlots();
6
+ slots.value = ctx.slots;
7
+ return () => ctx.slots.default?.();
8
+ });
9
+ //#endregion
10
+ export { forward_default as default };
@@ -0,0 +1,78 @@
1
+ require("@vue/compiler-dom");
2
+ let pathe = require("pathe");
3
+ //#region src/module/named-layout-slots/utils.ts
4
+ function isInDir(path, dir) {
5
+ const rel = (0, pathe.relative)(dir, path);
6
+ return rel !== ".." && !rel.startsWith("../") && !(0, pathe.isAbsolute)(rel);
7
+ }
8
+ //#endregion
9
+ //#region src/module/named-layout-slots/language.ts
10
+ const resolvedAsts = /* @__PURE__ */ new WeakSet();
11
+ const plugin = ({ modules: { typescript: ts, "@vue/compiler-dom": CompilerDOM }, config: { options } }) => ({
12
+ version: 2.2,
13
+ order: -1,
14
+ resolveEmbeddedCode(fileName, sfc, embeddedCode) {
15
+ if (!embeddedCode.id.startsWith("script_")) return;
16
+ if (!options.dirs.some((dir) => isInDir(fileName, dir))) return;
17
+ if (!sfc.template?.ast || resolvedAsts.has(sfc.template.ast)) return;
18
+ resolvedAsts.add(sfc.template.ast);
19
+ let layoutName = "default";
20
+ if (sfc.scriptSetup) visit(sfc.scriptSetup.ast);
21
+ function visit(node) {
22
+ if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "definePageMeta" && node.arguments.length && ts.isObjectLiteralExpression(node.arguments[0])) {
23
+ for (const prop of node.arguments[0].properties) if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === "layout" && ts.isStringLiteral(prop.initializer)) {
24
+ layoutName = prop.initializer.text;
25
+ break;
26
+ }
27
+ } else ts.forEachChild(node, visit);
28
+ }
29
+ const expression = `\n// @ts-ignore\n{} as import("#build/dxup/layouts").Layouts["${layoutName}"]\n`;
30
+ const children = sfc.template.ast.children;
31
+ sfc.template.ast.children = [{
32
+ type: CompilerDOM.NodeTypes.ELEMENT,
33
+ ns: CompilerDOM.Namespaces.HTML,
34
+ tag: "component",
35
+ tagType: CompilerDOM.ElementTypes.COMPONENT,
36
+ loc: createVirtualLoc(),
37
+ props: [{
38
+ type: CompilerDOM.NodeTypes.DIRECTIVE,
39
+ name: "bind",
40
+ arg: {
41
+ type: CompilerDOM.NodeTypes.SIMPLE_EXPRESSION,
42
+ content: "is",
43
+ isStatic: true,
44
+ constType: CompilerDOM.ConstantTypes.CAN_STRINGIFY,
45
+ loc: createVirtualLoc("is")
46
+ },
47
+ exp: {
48
+ type: CompilerDOM.NodeTypes.SIMPLE_EXPRESSION,
49
+ content: expression,
50
+ isStatic: false,
51
+ constType: CompilerDOM.ConstantTypes.NOT_CONSTANT,
52
+ loc: createVirtualLoc(expression)
53
+ },
54
+ modifiers: [],
55
+ loc: createVirtualLoc(`:is="${expression}"`)
56
+ }],
57
+ children,
58
+ codegenNode: void 0
59
+ }];
60
+ }
61
+ });
62
+ function createVirtualLoc(source = "") {
63
+ return {
64
+ start: {
65
+ line: Number.MAX_VALUE,
66
+ column: Number.MAX_VALUE,
67
+ offset: Number.MAX_VALUE
68
+ },
69
+ end: {
70
+ line: Number.MAX_VALUE,
71
+ column: Number.MAX_VALUE,
72
+ offset: Number.MAX_VALUE
73
+ },
74
+ source
75
+ };
76
+ }
77
+ //#endregion
78
+ module.exports = plugin;
@@ -0,0 +1,10 @@
1
+ import { VueLanguagePlugin } from "@vue/language-core";
2
+
3
+ //#region src/module/named-layout-slots/language.d.ts
4
+ interface Config {
5
+ options: {
6
+ dirs: string[];
7
+ };
8
+ }
9
+ declare const plugin: VueLanguagePlugin<Config>;
10
+ export = plugin;
package/dist/module.d.mts CHANGED
@@ -1,5 +1,3 @@
1
- import * as _nuxt_schema0 from "@nuxt/schema";
2
-
3
1
  //#region src/module/index.d.ts
4
2
  interface ModuleOptions {
5
3
  features?: {
@@ -13,6 +11,11 @@ interface ModuleOptions {
13
11
  * @default true
14
12
  */
15
13
  importGlob?: boolean;
14
+ /**
15
+ * Whether to enable named layout slots support in the pages.
16
+ * @default false
17
+ */
18
+ namedLayoutSlots?: boolean;
16
19
  /**
17
20
  * Whether to enable Go to Definition for nitro routes in data fetching methods.
18
21
  * @default true
@@ -46,10 +49,11 @@ interface ModuleOptions {
46
49
  unofficial?: boolean;
47
50
  };
48
51
  }
49
- declare const _default: _nuxt_schema0.NuxtModule<ModuleOptions, {
52
+ declare const _default: import("@nuxt/schema").NuxtModule<ModuleOptions, {
50
53
  features: {
51
54
  components: true;
52
55
  importGlob: true;
56
+ namedLayoutSlots: false;
53
57
  nitroRoutes: true;
54
58
  pageMeta: true;
55
59
  runtimeConfig: true;
package/dist/module.mjs CHANGED
@@ -1,13 +1,16 @@
1
- import { addTemplate, defineNuxtModule, useNitro } from "@nuxt/kit";
1
+ import { addBuildPlugin, addTemplate, addTypeTemplate, createResolver, defineNuxtModule, useNitro } from "@nuxt/kit";
2
2
  import { Buffer } from "node:buffer";
3
- import EventEmitter from "node:events";
3
+ import { EventEmitter } from "node:events";
4
4
  import { mkdir, open, readFile, writeFile } from "node:fs/promises";
5
5
  import { watch } from "chokidar";
6
- import { dirname, join } from "pathe";
7
-
6
+ import { dirname, isAbsolute, join, relative } from "pathe";
7
+ import { genExport, genImport, genInlineTypeImport, genObjectKey } from "knitwork";
8
+ import { ElementTypes, NodeTypes, parse } from "@vue/compiler-dom";
9
+ import MagicString from "magic-string";
10
+ import { createUnplugin } from "unplugin";
11
+ import { parseAndWalk } from "oxc-walker";
8
12
  //#region package.json
9
13
  var name = "@dxup/nuxt";
10
-
11
14
  //#endregion
12
15
  //#region src/event/client.ts
13
16
  const responseRE = /^```json \{(?<key>.*)\}\n(?<value>[\s\S]*?)\n```$/;
@@ -23,7 +26,7 @@ async function createEventClient(nuxt) {
23
26
  });
24
27
  const client = new EventEmitter();
25
28
  let offset = 0;
26
- watcher.on("change", async (path$1, stats) => {
29
+ watcher.on("change", async (path, stats) => {
27
30
  if (!stats || stats.size <= offset) return;
28
31
  const pos = offset;
29
32
  offset = stats.size;
@@ -37,18 +40,17 @@ async function createEventClient(nuxt) {
37
40
  });
38
41
  return client;
39
42
  }
40
-
41
43
  //#endregion
42
44
  //#region src/module/events.ts
43
45
  const uppercaseRE = /[A-Z]/;
44
46
  async function onComponentsRename(nuxt, { fileName, references }) {
45
47
  const component = Object.values(nuxt.apps).flatMap((app) => app.components).find((c) => c.filePath === fileName);
46
48
  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 tasks = Object.entries(references).map(async ([fileName, references]) => {
50
+ const code = await readFile(fileName, "utf-8");
49
51
  const chunks = [];
50
52
  let offset = 0;
51
- for (const { textSpan, lazy } of references$1) {
53
+ for (const { textSpan, lazy } of references) {
52
54
  const start = textSpan.start;
53
55
  const end = start + textSpan.length;
54
56
  const oldName = code.slice(start, end);
@@ -57,11 +59,165 @@ async function onComponentsRename(nuxt, { fileName, references }) {
57
59
  offset = end;
58
60
  }
59
61
  chunks.push(code.slice(offset));
60
- await writeFile(fileName$1, chunks.join(""));
62
+ await writeFile(fileName, chunks.join(""));
61
63
  });
62
64
  await Promise.all(tasks);
63
65
  }
64
-
66
+ //#endregion
67
+ //#region src/module/named-layout-slots/utils.ts
68
+ const vueRE = /[?&]vue(?:&|$)/;
69
+ const typeRE = /[?&]type=[^&]*/;
70
+ function isVue(id) {
71
+ const index = id.indexOf("?");
72
+ const query = index !== -1 ? id.slice(index) : void 0;
73
+ if (query === void 0) return id.endsWith(".vue");
74
+ if (query === "?macro=true") return true;
75
+ if (!vueRE.test(query)) return false;
76
+ if (typeRE.test(query)) return false;
77
+ return true;
78
+ }
79
+ function isInDir(path, dir) {
80
+ const rel = relative(dir, path);
81
+ return rel !== ".." && !rel.startsWith("../") && !isAbsolute(rel);
82
+ }
83
+ function parseSFC(code) {
84
+ const sfc = parse(code, { parseMode: "sfc" });
85
+ let scriptSetup;
86
+ let template;
87
+ for (const node of sfc.children) {
88
+ if (node.type !== NodeTypes.ELEMENT) continue;
89
+ if (node.tag === "script" && node.props.some((prop) => prop.type === NodeTypes.ATTRIBUTE && (prop.name === "setup" || prop.name === "vapor"))) scriptSetup = node;
90
+ else if (node.tag === "template") template = node;
91
+ }
92
+ return {
93
+ scriptSetup,
94
+ template
95
+ };
96
+ }
97
+ //#endregion
98
+ //#region src/module/named-layout-slots/plugins/transform-layout.ts
99
+ const TransformLayoutPlugin = (options) => createUnplugin(() => ({
100
+ name: name + ":transform-layout",
101
+ enforce: "pre",
102
+ transformInclude: isVue,
103
+ transform: {
104
+ filter: { code: /<(?:nuxt-layout|NuxtLayout)/ },
105
+ handler(code) {
106
+ const { scriptSetup, template } = parseSFC(code);
107
+ const layout = template?.children.find((node) => node.type === NodeTypes.ELEMENT && (node.tag === "nuxt-layout" || node.tag === "NuxtLayout"));
108
+ if (!layout?.children.length) return;
109
+ const s = new MagicString(code);
110
+ const prefix = "\n" + genImport("#build/dxup/layouts.mjs", ["provideLayoutSlots"]);
111
+ const suffix = `\nconst __dxup_layoutSlots = provideLayoutSlots();\n`;
112
+ if (scriptSetup) {
113
+ s.appendLeft(scriptSetup.innerLoc.start.offset, prefix);
114
+ s.appendLeft(scriptSetup.innerLoc.end.offset, suffix);
115
+ } else s.prepend(`<script setup>${prefix + suffix}<\/script>\n\n`);
116
+ s.appendLeft(layout.children.at(-1).loc.end.offset, `
117
+ <template v-for="name in $route.meta.layoutSlots ?? []" :key="name" #[name]="props">
118
+ <component :is="() => __dxup_layoutSlots[name]?.(props)"/>
119
+ </template>`);
120
+ return {
121
+ code: s.toString(),
122
+ map: options.sourcemap ? s.generateMap({ hires: true }) : void 0
123
+ };
124
+ }
125
+ }
126
+ }));
127
+ //#endregion
128
+ //#region src/module/named-layout-slots/plugins/transform-page.ts
129
+ const TransformPagePlugin = (options) => createUnplugin(() => ({
130
+ name: name + ":transform-page",
131
+ enforce: "pre",
132
+ transformInclude: isVue,
133
+ transform(code, id) {
134
+ if (!options.dirs.some((dir) => isInDir(id, dir))) return;
135
+ const { scriptSetup, template } = parseSFC(code);
136
+ if (!template) return;
137
+ const slots = [];
138
+ for (const node of template.children) {
139
+ if (node.type !== NodeTypes.ELEMENT || node.tagType !== ElementTypes.TEMPLATE) continue;
140
+ const dir = node.props.find((prop) => prop.type === NodeTypes.DIRECTIVE && prop.name === "slot");
141
+ if (dir?.arg?.type === NodeTypes.SIMPLE_EXPRESSION && dir.arg.isStatic && dir.arg.content !== "" && dir.arg.content !== "default") slots.push(dir.arg.content);
142
+ }
143
+ if (!slots.length) return;
144
+ const s = new MagicString(code);
145
+ const imports = genImport("#build/dxup/layouts.mjs", ["LayoutSlotsForward"]);
146
+ const expression = `layoutSlots: [${slots.map((slot) => JSON.stringify(slot)).join(", ")}],\n`;
147
+ if (scriptSetup) {
148
+ let meta;
149
+ parseAndWalk(scriptSetup.innerLoc.source, id, {
150
+ parseOptions: { lang: scriptSetup.props.find((prop) => prop.type === NodeTypes.ATTRIBUTE && prop.name === "lang")?.value?.content ?? "ts" },
151
+ enter(node) {
152
+ if (node.type === "CallExpression" && node.callee.type === "Identifier" && node.callee.name === "definePageMeta" && node.arguments[0]?.type === "ObjectExpression") {
153
+ meta = node.arguments[0];
154
+ this.skip();
155
+ }
156
+ }
157
+ });
158
+ const start = scriptSetup.innerLoc.start.offset;
159
+ s.appendLeft(start, `\n${imports}\n`);
160
+ if (meta) s.appendLeft(meta.properties[0].start + start, expression);
161
+ else s.appendLeft(scriptSetup.innerLoc.start.offset, `\ndefinePageMeta({\n${expression}});\n`);
162
+ } else s.prepend(`<script setup>\n${imports}\ndefinePageMeta({\n${expression}});\n<\/script>\n\n`);
163
+ s.appendLeft(template.innerLoc.start.offset, `<LayoutSlotsForward>`);
164
+ s.appendLeft(template.innerLoc.end.offset, "</LayoutSlotsForward>");
165
+ return {
166
+ code: s.toString(),
167
+ map: options.sourcemap ? s.generateMap({ hires: true }) : void 0
168
+ };
169
+ }
170
+ }));
171
+ //#endregion
172
+ //#region src/module/named-layout-slots/module.ts
173
+ function setup(nuxt, pluginsVue) {
174
+ const resolver = createResolver(import.meta.url);
175
+ const pageDirs = nuxt.options._layers.map((layer) => join(layer.config.srcDir, layer.config.dir?.pages ?? "pages"));
176
+ pluginsVue.push({
177
+ name: "@dxup/nuxt/languages/named-layout-slots.cjs",
178
+ options: { dirs: pageDirs }
179
+ });
180
+ addTemplate({
181
+ filename: "dxup/layouts.mjs",
182
+ getContents() {
183
+ return `
184
+ ${genImport("vue", [
185
+ "inject",
186
+ "provide",
187
+ "shallowRef"
188
+ ])}
189
+ ${genExport(resolver.resolve("components/forward"), [{
190
+ name: "default",
191
+ as: "LayoutSlotsForward"
192
+ }])}
193
+ const injectionKey = Symbol();
194
+ export function provideLayoutSlots() {
195
+ const slots = shallowRef({});
196
+ provide(injectionKey, slots);
197
+ return slots;
198
+ }
199
+ export function injectLayoutSlots() {
200
+ return inject(injectionKey);
201
+ }
202
+ `.trimStart();
203
+ }
204
+ });
205
+ addTypeTemplate({
206
+ filename: "dxup/layouts.d.ts",
207
+ getContents({ app }) {
208
+ return `
209
+ export interface Layouts {
210
+ ${Object.values(app.layouts).map((layout) => ` ${genObjectKey(layout.name)}: ${genInlineTypeImport(layout.file)};`).join("\n")}
211
+ }
212
+ `.trimStart();
213
+ }
214
+ });
215
+ addBuildPlugin(TransformPagePlugin({
216
+ dirs: pageDirs,
217
+ sourcemap: !!nuxt.options.sourcemap.client
218
+ }));
219
+ addBuildPlugin(TransformLayoutPlugin({ sourcemap: !!nuxt.options.sourcemap.client }));
220
+ }
65
221
  //#endregion
66
222
  //#region src/module/index.ts
67
223
  var module_default = defineNuxtModule().with({
@@ -72,6 +228,7 @@ var module_default = defineNuxtModule().with({
72
228
  defaults: { features: {
73
229
  components: true,
74
230
  importGlob: true,
231
+ namedLayoutSlots: false,
75
232
  nitroRoutes: true,
76
233
  pageMeta: true,
77
234
  runtimeConfig: true,
@@ -81,15 +238,18 @@ var module_default = defineNuxtModule().with({
81
238
  } },
82
239
  async setup(options, nuxt) {
83
240
  const pluginsTs = [{ name: "@dxup/nuxt" }];
84
- if (options.features?.unimport) pluginsTs.unshift({ name: "@dxup/unimport" });
241
+ const pluginsVue = [];
242
+ if (options.features.namedLayoutSlots) setup(nuxt, pluginsVue);
243
+ if (options.features.unimport) pluginsTs.unshift({ name: "@dxup/unimport" });
85
244
  append(pluginsTs, nuxt.options, "typescript", "tsConfig", "compilerOptions");
86
245
  append(pluginsTs, nuxt.options.nitro, "typescript", "tsConfig", "compilerOptions");
87
246
  append(pluginsTs, nuxt.options, "typescript", "sharedTsConfig", "compilerOptions");
88
247
  append(pluginsTs, nuxt.options, "typescript", "nodeTsConfig", "compilerOptions");
248
+ append(pluginsVue, nuxt.options, "typescript", "tsConfig", "vueCompilerOptions");
89
249
  addTemplate({
90
250
  filename: "dxup/data.json",
91
251
  write: true,
92
- getContents({ nuxt: nuxt$1, app }) {
252
+ getContents({ nuxt, app }) {
93
253
  const layouts = Object.fromEntries(Object.values(app.layouts).map((item) => [item.name, item.file]));
94
254
  const middleware = app.middleware.reduce((acc, item) => {
95
255
  if (!item.global) acc[item.name] = item.path;
@@ -105,9 +265,9 @@ var module_default = defineNuxtModule().with({
105
265
  return acc;
106
266
  }, {});
107
267
  const data = {
108
- buildDir: nuxt$1.options.buildDir,
109
- publicDir: nuxt$1.options.dir.public,
110
- configFiles: [...nuxt$1.options._nuxtConfigFiles, ...nuxt$1.options._layers.map((layer) => layer._configFile).filter(Boolean)],
268
+ buildDir: nuxt.options.buildDir,
269
+ publicDir: nuxt.options.dir.public,
270
+ configFiles: [...nuxt.options._nuxtConfigFiles, ...nuxt.options._layers.map((layer) => layer._configFile).filter(Boolean)],
111
271
  layouts,
112
272
  middleware,
113
273
  nitroRoutes,
@@ -124,6 +284,5 @@ function append(plugins, target, ...keys) {
124
284
  for (const key of keys) target = target[key] ??= {};
125
285
  (target.plugins ??= []).push(...plugins);
126
286
  }
127
-
128
287
  //#endregion
129
- export { module_default as default };
288
+ export { module_default as default };
@@ -1,24 +1,18 @@
1
- //#region rolldown:runtime
1
+ //#region \0rolldown/runtime.js
2
2
  var __defProp = Object.defineProperty;
3
- var __export = (all, symbols) => {
3
+ var __exportAll = (all, no_symbols) => {
4
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
- }
5
+ for (var name in all) __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true
8
+ });
9
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
14
10
  return target;
15
11
  };
16
-
17
12
  //#endregion
18
13
  let node_fs_promises = require("node:fs/promises");
19
14
  let pathe = require("pathe");
20
15
  let tinyglobby = require("tinyglobby");
21
-
22
16
  //#region src/event/server.ts
23
17
  function createEventServer(info) {
24
18
  const path = (0, pathe.join)(info.project.getCurrentDirectory(), "dxup/events.md");
@@ -29,7 +23,6 @@ function createEventServer(info) {
29
23
  }
30
24
  return { write };
31
25
  }
32
-
33
26
  //#endregion
34
27
  //#region src/typescript/data.ts
35
28
  const initialValue = {
@@ -55,20 +48,19 @@ function createData(ts, info) {
55
48
  const path = (0, pathe.join)(info.languageServiceHost.getCurrentDirectory(), "dxup/data.json");
56
49
  const data = {};
57
50
  const updates = callbacks[path] ??= (ts.sys.watchFile?.(path, () => {
58
- const text$1 = ts.sys.readFile(path);
59
- for (const update of updates) update(text$1);
51
+ const text = ts.sys.readFile(path);
52
+ for (const update of updates) update(text);
60
53
  }), []);
61
- updates.push((text$1) => {
54
+ updates.push((text) => {
62
55
  Object.assign(data, {
63
56
  ...initialValue,
64
- ...text$1 ? JSON.parse(text$1) : {}
57
+ ...text ? JSON.parse(text) : {}
65
58
  });
66
59
  });
67
60
  const text = ts.sys.readFile(path);
68
61
  updates.at(-1)(text);
69
62
  return data;
70
63
  }
71
-
72
64
  //#endregion
73
65
  //#region src/typescript/utils.ts
74
66
  function createModuleDefinition(ts, path) {
@@ -115,10 +107,9 @@ function withVirtualOffset(language, sourceScript, position, method) {
115
107
  map.toGeneratedLocation = original;
116
108
  }
117
109
  }
118
-
119
110
  //#endregion
120
111
  //#region src/typescript/features/findReferences.ts
121
- var findReferences_exports = /* @__PURE__ */ __export({ postprocess: () => postprocess$1 });
112
+ var findReferences_exports = /* @__PURE__ */ __exportAll({ postprocess: () => postprocess$1 });
122
113
  function postprocess$1(context, language, findReferences) {
123
114
  const { ts, info } = context;
124
115
  return (...args) => {
@@ -137,10 +128,9 @@ function postprocess$1(context, language, findReferences) {
137
128
  return result;
138
129
  };
139
130
  }
140
-
141
131
  //#endregion
142
132
  //#region src/typescript/features/findRenameLocations.ts
143
- var findRenameLocations_exports = /* @__PURE__ */ __export({ preprocess: () => preprocess$2 });
133
+ var findRenameLocations_exports = /* @__PURE__ */ __exportAll({ preprocess: () => preprocess$2 });
144
134
  function preprocess$2(context, findRenameLocations) {
145
135
  const { data } = context;
146
136
  return (...args) => {
@@ -149,7 +139,6 @@ function preprocess$2(context, findRenameLocations) {
149
139
  });
150
140
  };
151
141
  }
152
-
153
142
  //#endregion
154
143
  //#region ../shared/src/index.ts
155
144
  function* forEachTouchingNode(ts, sourceFile, position) {
@@ -164,12 +153,12 @@ function* binaryVisit(ts, sourceFile, node, position) {
164
153
  let right = nodes.length - 1;
165
154
  while (left <= right) {
166
155
  const mid = Math.floor((left + right) / 2);
167
- const node$1 = nodes[mid];
168
- if (position > node$1.getEnd()) left = mid + 1;
169
- else if (position < node$1.getStart(sourceFile)) right = mid - 1;
156
+ const node = nodes[mid];
157
+ if (position > node.getEnd()) left = mid + 1;
158
+ else if (position < node.getStart(sourceFile)) right = mid - 1;
170
159
  else {
171
- yield node$1;
172
- yield* binaryVisit(ts, sourceFile, node$1, position);
160
+ yield node;
161
+ yield* binaryVisit(ts, sourceFile, node, position);
173
162
  return;
174
163
  }
175
164
  }
@@ -177,10 +166,9 @@ function* binaryVisit(ts, sourceFile, node, position) {
177
166
  function isTextSpanWithin(node, textSpan, sourceFile) {
178
167
  return textSpan.start + textSpan.length <= node.getEnd() && textSpan.start >= node.getStart(sourceFile);
179
168
  }
180
-
181
169
  //#endregion
182
170
  //#region src/typescript/features/getDefinitionAndBoundSpan.ts
183
- var getDefinitionAndBoundSpan_exports = /* @__PURE__ */ __export({
171
+ var getDefinitionAndBoundSpan_exports = /* @__PURE__ */ __exportAll({
184
172
  postprocess: () => postprocess,
185
173
  preprocess: () => preprocess$1
186
174
  });
@@ -222,18 +210,18 @@ function preprocess$1(context, getDefinitionAndBoundSpan) {
222
210
  return (...args) => {
223
211
  const result = getDefinitionAndBoundSpan(...args);
224
212
  if (!result) {
225
- const program$1 = info.languageService.getProgram();
226
- const sourceFile = program$1.getSourceFile(args[0]);
213
+ const program = info.languageService.getProgram();
214
+ const sourceFile = program.getSourceFile(args[0]);
227
215
  if (!sourceFile) return;
228
- const checker = program$1.getTypeChecker();
229
- let result$1;
216
+ const checker = program.getTypeChecker();
217
+ let result;
230
218
  for (const node of forEachTouchingNode(ts, sourceFile, args[1])) {
231
- if (data.features.importGlob) result$1 ??= visitImportGlob(ts, info, sourceFile, node, args[1]);
232
- if (data.features.nitroRoutes) result$1 ??= visitNitroRoutes(ts, data, checker, sourceFile, node, args[1]);
233
- if (data.features.pageMeta) result$1 ??= visitPageMeta(ts, data, sourceFile, node, args[1]);
234
- if (data.features.typedPages) result$1 ??= visitTypedPages(ts, data, checker, sourceFile, node, args[1]);
219
+ if (data.features.importGlob) result ??= visitImportGlob(ts, info, sourceFile, node, args[1]);
220
+ if (data.features.nitroRoutes) result ??= visitNitroRoutes(ts, data, checker, sourceFile, node, args[1]);
221
+ if (data.features.pageMeta) result ??= visitPageMeta(ts, data, sourceFile, node, args[1]);
222
+ if (data.features.typedPages) result ??= visitTypedPages(ts, data, checker, sourceFile, node, args[1]);
235
223
  }
236
- if (result$1) return result$1;
224
+ if (result) return result;
237
225
  }
238
226
  if (!result?.definitions?.length) return result;
239
227
  const program = info.languageService.getProgram();
@@ -241,10 +229,10 @@ function preprocess$1(context, getDefinitionAndBoundSpan) {
241
229
  for (const definition of result.definitions) {
242
230
  const sourceFile = program.getSourceFile(definition.fileName);
243
231
  if (!sourceFile) continue;
244
- let result$1;
245
- if (data.features.runtimeConfig && definition.fileName.endsWith("runtime-config.d.ts")) result$1 = visitRuntimeConfig(context, sourceFile, definition);
246
- if (result$1?.length) {
247
- for (const definition$1 of result$1) definitions.add(definition$1);
232
+ let result;
233
+ if (data.features.runtimeConfig && definition.fileName.endsWith("runtime-config.d.ts")) result = visitRuntimeConfig(context, sourceFile, definition);
234
+ if (result?.length) {
235
+ for (const definition of result) definitions.add(definition);
248
236
  definitions.delete(definition);
249
237
  }
250
238
  }
@@ -328,11 +316,19 @@ function visitPageMeta(ts, data, sourceFile, node, position) {
328
316
  if (!ts.isPropertyAssignment(node) || !ts.isIdentifier(node.name) || !pageMetaKeys.has(node.name.text) || !ts.isCallExpression(node.parent.parent) || !ts.isIdentifier(node.parent.parent.expression) || node.parent.parent.expression.text !== "definePageMeta") return;
329
317
  switch (node.name.text) {
330
318
  case "layout": {
331
- if (!ts.isStringLiteralLike(node.initializer)) return;
332
- const start = node.initializer.getStart(sourceFile);
333
- const end = node.initializer.getEnd();
319
+ let literal;
320
+ if (ts.isStringLiteralLike(node.initializer)) literal = node.initializer;
321
+ else if (ts.isObjectLiteralExpression(node.initializer)) {
322
+ for (const prop of node.initializer.properties) if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === "name" && ts.isStringLiteralLike(prop.initializer)) {
323
+ literal = prop.initializer;
324
+ break;
325
+ }
326
+ }
327
+ if (!literal) return;
328
+ const start = literal.getStart(sourceFile);
329
+ const end = literal.getEnd();
334
330
  if (position < start || position > end) return;
335
- const path = data.layouts[node.initializer.text];
331
+ const path = data.layouts[literal.text];
336
332
  if (path === void 0) return;
337
333
  return {
338
334
  textSpan: {
@@ -418,8 +414,8 @@ function* forwardRuntimeConfig(context, definition, path) {
418
414
  const nodeProgram = nodeProject.getLanguageService().getProgram();
419
415
  if (!nodeProgram) return;
420
416
  const checker = nodeProgram.getTypeChecker();
421
- for (const configFile$1 of data.configFiles) {
422
- const sourceFile = nodeProgram.getSourceFile(configFile$1);
417
+ for (const configFile of data.configFiles) {
418
+ const sourceFile = nodeProgram.getSourceFile(configFile);
423
419
  if (!sourceFile) continue;
424
420
  outer: for (const node of sourceFile.statements) {
425
421
  if (!ts.isExportAssignment(node) || !ts.isCallExpression(node.expression) || !node.expression.arguments.length) continue;
@@ -433,19 +429,19 @@ function* forwardRuntimeConfig(context, definition, path) {
433
429
  currentType = checker.getTypeOfSymbol(symbol);
434
430
  }
435
431
  for (const decl of currentSymbol?.declarations ?? []) {
436
- const sourceFile$1 = decl.getSourceFile();
432
+ const sourceFile = decl.getSourceFile();
437
433
  const contextSpan = {
438
- start: decl.getStart(sourceFile$1),
439
- length: decl.getWidth(sourceFile$1)
434
+ start: decl.getStart(sourceFile),
435
+ length: decl.getWidth(sourceFile)
440
436
  };
441
437
  let textSpan = contextSpan;
442
438
  if (ts.isPropertyAssignment(decl) || ts.isPropertySignature(decl)) textSpan = {
443
- start: decl.name.getStart(sourceFile$1),
444
- length: decl.name.getWidth(sourceFile$1)
439
+ start: decl.name.getStart(sourceFile),
440
+ length: decl.name.getWidth(sourceFile)
445
441
  };
446
442
  yield {
447
443
  ...definition,
448
- fileName: sourceFile$1.fileName,
444
+ fileName: sourceFile.fileName,
449
445
  textSpan,
450
446
  contextSpan
451
447
  };
@@ -453,10 +449,9 @@ function* forwardRuntimeConfig(context, definition, path) {
453
449
  }
454
450
  }
455
451
  }
456
-
457
452
  //#endregion
458
453
  //#region src/typescript/features/getEditsForFileRename.ts
459
- var getEditsForFileRename_exports = /* @__PURE__ */ __export({ preprocess: () => preprocess });
454
+ var getEditsForFileRename_exports = /* @__PURE__ */ __exportAll({ preprocess: () => preprocess });
460
455
  function preprocess(context, getEditsForFileRename) {
461
456
  const { ts, info, data, server } = context;
462
457
  return (...args) => {
@@ -475,7 +470,7 @@ function preprocess(context, getEditsForFileRename) {
475
470
  const position = node.name.getStart(sourceFile);
476
471
  const res = languageService.getReferencesAtPosition(fileName, position)?.filter((entry) => !entry.fileName.startsWith(data.buildDir))?.sort((a, b) => a.textSpan.start - b.textSpan.start);
477
472
  const lazy = node.type && ts.isTypeReferenceNode(node.type) && ts.isIdentifier(node.type.typeName) && node.type.typeName.text === "LazyComponent";
478
- for (const { fileName: fileName$1, textSpan } of res ?? []) (references[fileName$1] ??= []).push({
473
+ for (const { fileName, textSpan } of res ?? []) (references[fileName] ??= []).push({
479
474
  textSpan,
480
475
  lazy: lazy || void 0
481
476
  });
@@ -492,11 +487,10 @@ function preprocess(context, getEditsForFileRename) {
492
487
  });
493
488
  };
494
489
  }
495
-
496
490
  //#endregion
497
491
  //#region src/typescript/index.ts
498
- const plugin = (module$1) => {
499
- const { typescript: ts } = module$1;
492
+ const plugin = (module) => {
493
+ const { typescript: ts } = module;
500
494
  return { create(info) {
501
495
  const data = createData(ts, info);
502
496
  const context = {
@@ -514,14 +508,9 @@ const plugin = (module$1) => {
514
508
  const original = languageService[key];
515
509
  methods[key] = method.postprocess(context, context.language, original);
516
510
  }
517
- info.project["languageService"] = new Proxy(languageService, {
518
- get(target, p, receiver) {
519
- return methods[p] ?? Reflect.get(target, p, receiver);
520
- },
521
- set(...args) {
522
- return Reflect.set(...args);
523
- }
524
- });
511
+ info.project["languageService"] = new Proxy(languageService, { get(target, p, receiver) {
512
+ return methods[p] ?? Reflect.get(target, p, receiver);
513
+ } });
525
514
  });
526
515
  for (const [key, method] of [
527
516
  ["findRenameLocations", findRenameLocations_exports],
@@ -534,7 +523,5 @@ const plugin = (module$1) => {
534
523
  return info.languageService;
535
524
  } };
536
525
  };
537
- var typescript_default = plugin;
538
-
539
526
  //#endregion
540
- module.exports = typescript_default;
527
+ module.exports = plugin;
package/package.json CHANGED
@@ -1,13 +1,18 @@
1
1
  {
2
2
  "name": "@dxup/nuxt",
3
3
  "type": "module",
4
- "version": "0.4.0",
4
+ "version": "0.5.0",
5
5
  "description": "TypeScript plugin for Nuxt",
6
6
  "author": "KazariEX",
7
7
  "license": "MIT",
8
- "repository": "KazariEX/dxup",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "KazariEX/dxup"
11
+ },
9
12
  "exports": {
10
13
  ".": "./dist/module.mjs",
14
+ "./components/*": "./dist/components/*",
15
+ "./languages/*": "./dist/languages/*",
11
16
  "./package.json": "./package.json"
12
17
  },
13
18
  "main": "./dist/typescript.cjs",
@@ -15,23 +20,25 @@
15
20
  "files": [
16
21
  "dist"
17
22
  ],
18
- "peerDependencies": {
19
- "typescript": "*"
20
- },
21
23
  "dependencies": {
22
- "@nuxt/kit": "^4.2.2",
24
+ "@nuxt/kit": "^4.4.8",
25
+ "@vue/compiler-dom": "^3.5.38",
23
26
  "chokidar": "^5.0.0",
27
+ "knitwork": "^1.3.0",
28
+ "magic-string": "^0.30.21",
29
+ "oxc-walker": "^1.0.0",
24
30
  "pathe": "^2.0.3",
25
- "tinyglobby": "^0.2.15",
31
+ "tinyglobby": "^0.2.17",
32
+ "unplugin": "^3.0.0",
26
33
  "@dxup/unimport": "^0.1.2"
27
34
  },
28
35
  "devDependencies": {
29
- "@dxup/shared": "",
30
- "@volar/language-core": "^2.4.27",
31
- "@volar/typescript": "^2.4.27",
32
- "@vue/language-core": "^3.2.1",
33
- "nuxt": "^4.2.2",
34
- "typescript": "^5.9.3"
36
+ "@volar/language-core": "^2.4.28",
37
+ "@volar/typescript": "^2.4.28",
38
+ "@vue/language-core": "^3.3.5",
39
+ "nuxt": "^4.4.8",
40
+ "typescript": "^6.0.3",
41
+ "@dxup/shared": "0.0.0"
35
42
  },
36
43
  "scripts": {
37
44
  "build": "tsdown",