wesl-plugin 0.6.70 → 0.6.72

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.
@@ -1,9 +1,7 @@
1
- import { n as weslPlugin } from "../WeslPlugin-BKQJvQve.mjs";
2
- import "../StaticExtension-Chl5KPpw.mjs";
1
+ import { n as weslPlugin } from "../WeslPlugin-B91dE_tA.mjs";
2
+ import "../StaticExtension-CDqA2teq.mjs";
3
3
  import { createFarmPlugin } from "unplugin";
4
-
5
4
  //#region src/plugins/farm.ts
6
5
  var farm_default = createFarmPlugin(weslPlugin);
7
-
8
6
  //#endregion
9
- export { farm_default as default };
7
+ export { farm_default as default };
@@ -1,4 +1,4 @@
1
- import { t as WeslPluginOptions } from "../WeslPluginOptions-DWIrd183.mjs";
1
+ import { t as WeslPluginOptions } from "../WeslPluginOptions-D81oyynl.mjs";
2
2
  import * as _nuxt_schema0 from "@nuxt/schema";
3
3
 
4
4
  //#region src/plugins/nuxt.d.ts
@@ -1,10 +1,9 @@
1
- import "../WeslPlugin-BKQJvQve.mjs";
2
- import "../StaticExtension-Chl5KPpw.mjs";
1
+ import "../WeslPlugin-B91dE_tA.mjs";
2
+ import "../StaticExtension-CDqA2teq.mjs";
3
3
  import vite_default from "./vite.mjs";
4
4
  import webpack_default from "./webpack.mjs";
5
5
  import { addVitePlugin, addWebpackPlugin, defineNuxtModule } from "@nuxt/kit";
6
6
  import "@nuxt/schema";
7
-
8
7
  //#region src/plugins/nuxt.ts
9
8
  var nuxt_default = defineNuxtModule({
10
9
  meta: {
@@ -17,6 +16,5 @@ var nuxt_default = defineNuxtModule({
17
16
  addWebpackPlugin(() => webpack_default(options));
18
17
  }
19
18
  });
20
-
21
19
  //#endregion
22
- export { nuxt_default as default };
20
+ export { nuxt_default as default };
@@ -1,4 +1,4 @@
1
- import { t as WeslPluginOptions } from "../WeslPluginOptions-DWIrd183.mjs";
1
+ import { t as WeslPluginOptions } from "../WeslPluginOptions-D81oyynl.mjs";
2
2
  import * as rollup from "rollup";
3
3
 
4
4
  //#region src/plugins/rollup.d.ts
@@ -1,9 +1,7 @@
1
- import { n as weslPlugin } from "../WeslPlugin-BKQJvQve.mjs";
2
- import "../StaticExtension-Chl5KPpw.mjs";
1
+ import { n as weslPlugin } from "../WeslPlugin-B91dE_tA.mjs";
2
+ import "../StaticExtension-CDqA2teq.mjs";
3
3
  import { createRollupPlugin } from "unplugin";
4
-
5
4
  //#region src/plugins/rollup.ts
6
5
  var rollup_default = createRollupPlugin(weslPlugin);
7
-
8
6
  //#endregion
9
- export { rollup_default as default };
7
+ export { rollup_default as default };
@@ -1,4 +1,4 @@
1
- import { t as WeslPluginOptions } from "../WeslPluginOptions-DWIrd183.mjs";
1
+ import { t as WeslPluginOptions } from "../WeslPluginOptions-D81oyynl.mjs";
2
2
 
3
3
  //#region src/plugins/rspack.d.ts
4
4
  declare const _default: (options?: WeslPluginOptions | undefined) => RspackPluginInstance;
@@ -1,9 +1,7 @@
1
- import { n as weslPlugin } from "../WeslPlugin-BKQJvQve.mjs";
2
- import "../StaticExtension-Chl5KPpw.mjs";
1
+ import { n as weslPlugin } from "../WeslPlugin-B91dE_tA.mjs";
2
+ import "../StaticExtension-CDqA2teq.mjs";
3
3
  import { createRspackPlugin } from "unplugin";
4
-
5
4
  //#region src/plugins/rspack.ts
6
5
  var rspack_default = createRspackPlugin(weslPlugin);
7
-
8
6
  //#endregion
9
- export { rspack_default as default };
7
+ export { rspack_default as default };
@@ -1,4 +1,4 @@
1
- import { t as WeslPluginOptions } from "../WeslPluginOptions-DWIrd183.mjs";
1
+ import { t as WeslPluginOptions } from "../WeslPluginOptions-D81oyynl.mjs";
2
2
  import * as vite from "vite";
3
3
 
4
4
  //#region src/plugins/vite.d.ts
@@ -1,9 +1,7 @@
1
- import { n as weslPlugin } from "../WeslPlugin-BKQJvQve.mjs";
2
- import "../StaticExtension-Chl5KPpw.mjs";
1
+ import { n as weslPlugin } from "../WeslPlugin-B91dE_tA.mjs";
2
+ import "../StaticExtension-CDqA2teq.mjs";
3
3
  import { createVitePlugin } from "unplugin";
4
-
5
4
  //#region src/plugins/vite.ts
6
5
  var vite_default = createVitePlugin(weslPlugin);
7
-
8
6
  //#endregion
9
- export { vite_default as default };
7
+ export { vite_default as default };
@@ -1,4 +1,4 @@
1
- import { t as WeslPluginOptions } from "../WeslPluginOptions-DWIrd183.mjs";
1
+ import { t as WeslPluginOptions } from "../WeslPluginOptions-D81oyynl.mjs";
2
2
  import * as webpack from "webpack";
3
3
 
4
4
  //#region src/plugins/webpack.d.ts
@@ -1,9 +1,7 @@
1
- import { n as weslPlugin } from "../WeslPlugin-BKQJvQve.mjs";
2
- import "../StaticExtension-Chl5KPpw.mjs";
1
+ import { n as weslPlugin } from "../WeslPlugin-B91dE_tA.mjs";
2
+ import "../StaticExtension-CDqA2teq.mjs";
3
3
  import { createWebpackPlugin } from "unplugin";
4
-
5
4
  //#region src/plugins/webpack.ts
6
5
  var webpack_default = createWebpackPlugin(weslPlugin);
7
-
8
6
  //#endregion
9
- export { webpack_default as default };
7
+ export { webpack_default as default };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "wesl-plugin",
3
3
  "description": "",
4
- "version": "0.6.70",
4
+ "version": "0.6.72",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "src",
@@ -25,7 +25,8 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "unplugin": "^2.3.5",
28
- "wesl": "0.7.22"
28
+ "wesl": "0.7.24",
29
+ "wesl-reflect": "0.0.3"
29
30
  },
30
31
  "devDependencies": {
31
32
  "@nuxt/kit": "^3.17.6",
@@ -34,6 +35,7 @@
34
35
  "chalk": "^5.4.1",
35
36
  "import-meta-resolve": "^4.1.0",
36
37
  "nodemon": "^3.1.10",
38
+ "random_wgsl": "x",
37
39
  "rollup": "^4.44.1",
38
40
  "toml": "^3.0.0",
39
41
  "webpack": "^5.99.9",
package/src/PluginApi.ts CHANGED
@@ -2,29 +2,79 @@ import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { glob } from "glob";
4
4
  import type { UnpluginBuildContext, UnpluginContext } from "unplugin";
5
- import { RecordResolver } from "wesl";
5
+ import {
6
+ discoverModules,
7
+ fileToModulePath,
8
+ freshResolver,
9
+ RecordResolver,
10
+ } from "wesl";
6
11
  import {
7
12
  findWeslToml,
8
13
  parseDependencies,
14
+ resolvePkgDeps,
9
15
  type WeslTomlInfo,
10
16
  } from "wesl-tooling";
11
- import type { PluginExtensionApi } from "./PluginExtension.ts";
17
+ import type { PluginExtensionApi, ProjectSources } from "./PluginExtension.ts";
12
18
  import type { PluginContext } from "./WeslPlugin.ts";
13
19
 
20
+ /** Construct the API surface available to plugin extensions. */
14
21
  export function buildApi(
15
22
  context: PluginContext,
16
23
  unpluginCtx: UnpluginBuildContext & UnpluginContext,
17
24
  ): PluginExtensionApi {
18
- return {
25
+ const api: PluginExtensionApi = {
19
26
  weslToml: async () => getWeslToml(context, unpluginCtx),
20
27
  weslSrc: async () => loadWesl(context, unpluginCtx),
21
28
  weslRegistry: async () => getRegistry(context, unpluginCtx),
22
29
  weslMain: makeGetWeslMain(context, unpluginCtx),
23
30
  weslDependencies: async () => findDependencies(context, unpluginCtx),
31
+ debugWeslRoot: async () => getDebugWeslRoot(context, unpluginCtx),
32
+ scopedProject: rootModuleName =>
33
+ getScopedProject(rootModuleName, context, unpluginCtx),
34
+ fetchProject: (rootModuleName, options) =>
35
+ fetchProject(api, rootModuleName, options),
24
36
  };
37
+ return api;
38
+ }
39
+
40
+ /** Get weslSrc scoped to modules reachable from root, plus their deps. */
41
+ async function getScopedProject(
42
+ rootModuleName: string,
43
+ context: PluginContext,
44
+ unpluginCtx: UnpluginBuildContext & UnpluginContext,
45
+ ): Promise<ProjectSources> {
46
+ const fullSrc = await loadWesl(context, unpluginCtx);
47
+ const { toml, tomlDir: projectDir } = await getWeslToml(context, unpluginCtx);
48
+
49
+ const registry = await getRegistry(context, unpluginCtx);
50
+ const resolver = freshResolver(registry);
51
+ const modulePath = fileToModulePath(rootModuleName, "package", false);
52
+ const { weslSrc, unbound } = discoverModules(fullSrc, resolver, modulePath);
53
+ const dependencies = resolveDepsFromUnbound(
54
+ toml.dependencies,
55
+ unbound,
56
+ projectDir,
57
+ );
58
+ return { weslSrc, dependencies };
59
+ }
60
+
61
+ /** Resolve dependencies using pre-computed unbound refs (avoids re-parsing). */
62
+ function resolveDepsFromUnbound(
63
+ dependencies: string | string[] | undefined,
64
+ unbound: string[][],
65
+ projectDir: string,
66
+ ): string[] {
67
+ const depsArray = Array.isArray(dependencies)
68
+ ? dependencies
69
+ : [dependencies ?? "auto"];
70
+ if (!depsArray.includes("auto")) return depsArray;
71
+
72
+ const base = depsArray.filter(dep => dep !== "auto");
73
+ const discovered = resolvePkgDeps(unbound, projectDir);
74
+ return [...new Set([...base, ...discovered])];
25
75
  }
26
76
 
27
- /** load the wesl.toml */
77
+ /** Load and cache the wesl.toml configuration. */
28
78
  export async function getWeslToml(
29
79
  context: PluginContext,
30
80
  unpluginCtx: UnpluginBuildContext & UnpluginContext,
@@ -32,8 +82,7 @@ export async function getWeslToml(
32
82
  const { cache } = context;
33
83
  if (cache.weslToml) return cache.weslToml;
34
84
 
35
- const specifiedToml = context.options.weslToml;
36
- const tomlInfo = await findWeslToml(process.cwd(), specifiedToml);
85
+ const tomlInfo = await findWeslToml(process.cwd(), context.options.weslToml);
37
86
 
38
87
  if (tomlInfo.tomlFile) {
39
88
  unpluginCtx.addWatchFile(tomlInfo.tomlFile); // The cache gets cleared by the watchChange hook
@@ -41,10 +90,10 @@ export async function getWeslToml(
41
90
  }
42
91
 
43
92
  cache.weslToml = tomlInfo;
44
- return cache.weslToml;
93
+ return tomlInfo;
45
94
  }
46
95
 
47
- /** load and parse all the wesl files into a ParsedRegistry */
96
+ /** Load all wesl files and return a cached RecordResolver. */
48
97
  async function getRegistry(
49
98
  context: PluginContext,
50
99
  unpluginCtx: UnpluginBuildContext & UnpluginContext,
@@ -53,7 +102,6 @@ async function getRegistry(
53
102
  let { registry } = cache;
54
103
  if (registry) return registry;
55
104
 
56
- // load wesl files into registry
57
105
  const loaded = await loadWesl(context, unpluginCtx);
58
106
  const { resolvedRoot } = await getWeslToml(context, unpluginCtx);
59
107
 
@@ -62,35 +110,64 @@ async function getRegistry(
62
110
  // The paths are relative to the weslRoot, but vite needs actual filesystem paths
63
111
  const fullPaths = Object.keys(loaded).map(p => path.resolve(resolvedRoot, p));
64
112
 
65
- // trigger clearing cache on shader file change
66
- fullPaths.forEach(f => {
67
- unpluginCtx.addWatchFile(f);
68
- });
113
+ for (const f of fullPaths) unpluginCtx.addWatchFile(f);
69
114
 
70
115
  cache.registry = registry;
71
116
  return registry;
72
117
  }
73
118
 
74
- /** if the dependency list includes "auto", fill in the missing dependencies
75
- * by parsing the source files to find references to packages
76
- * @return the list of dependencies with "auto" replaced by the found dependencies
77
- */
119
+ /** Compute weslRoot relative to tomlDir, with forward slashes. */
120
+ async function getDebugWeslRoot(
121
+ context: PluginContext,
122
+ unpluginCtx: UnpluginBuildContext & UnpluginContext,
123
+ ): Promise<string> {
124
+ const { resolvedRoot, tomlDir } = await getWeslToml(context, unpluginCtx);
125
+ return toUnixPath(path.relative(tomlDir, resolvedRoot));
126
+ }
127
+
128
+ /** Fetch project sources, either all or scoped to reachable modules. */
129
+ async function fetchProject(
130
+ api: PluginExtensionApi,
131
+ rootModuleName: string,
132
+ options?: Record<string, string>,
133
+ ): Promise<ProjectSources> {
134
+ if (options?.include === "all") {
135
+ const [weslSrc, dependencies] = await Promise.all([
136
+ api.weslSrc(),
137
+ api.weslDependencies(),
138
+ ]);
139
+ return { weslSrc, dependencies };
140
+ }
141
+ return api.scopedProject(rootModuleName);
142
+ }
143
+
144
+ /** Find dependencies, resolving "auto" entries by parsing source files. */
78
145
  async function findDependencies(
79
146
  context: PluginContext,
80
147
  unpluginCtx: UnpluginBuildContext & UnpluginContext,
81
148
  ): Promise<string[]> {
82
149
  const { toml, tomlDir: projectDir } = await getWeslToml(context, unpluginCtx);
83
150
  const weslSrc = await loadWesl(context, unpluginCtx);
84
- const { dependencies = "auto" } = toml;
85
- const depsArray = Array.isArray(dependencies) ? dependencies : [dependencies];
151
+ return resolveDeps(toml.dependencies, weslSrc, projectDir);
152
+ }
153
+
154
+ /** Resolve the dependency list, replacing "auto" entries with discovered deps. */
155
+ function resolveDeps(
156
+ dependencies: string | string[] | undefined,
157
+ weslSrc: Record<string, string>,
158
+ projectDir: string,
159
+ ): string[] {
160
+ const depsArray = Array.isArray(dependencies)
161
+ ? dependencies
162
+ : [dependencies ?? "auto"];
86
163
  if (!depsArray.includes("auto")) return depsArray;
87
164
 
88
165
  const base = depsArray.filter(dep => dep !== "auto");
89
- const deps = parseDependencies(weslSrc, projectDir);
90
- const combined = new Set([...base, ...deps]);
91
- return [...combined];
166
+ const discovered = parseDependencies(weslSrc, projectDir);
167
+ return [...new Set([...base, ...discovered])];
92
168
  }
93
169
 
170
+ /** @return a function that resolves a shader path to a weslRoot-relative module path. */
94
171
  function makeGetWeslMain(
95
172
  context: PluginContext,
96
173
  unpluginContext: UnpluginBuildContext & UnpluginContext,
@@ -111,55 +188,40 @@ function makeGetWeslMain(
111
188
  }
112
189
  }
113
190
 
114
- /**
115
- * Load the wesl files referenced in the wesl.toml file
116
- *
117
- * @return a record of wesl files with
118
- * keys as wesl file paths, and
119
- * values as wesl file contents.
120
- */
191
+ /** Load wesl files referenced in wesl.toml as a path-to-contents record. */
121
192
  async function loadWesl(
122
193
  context: PluginContext,
123
194
  unpluginCtx: UnpluginBuildContext & UnpluginContext,
124
195
  ): Promise<Record<string, string>> {
125
- const {
126
- toml: { include },
127
- resolvedRoot,
128
- tomlDir,
129
- } = await getWeslToml(context, unpluginCtx);
196
+ const tomlInfo = await getWeslToml(context, unpluginCtx);
197
+ const { resolvedRoot, tomlDir } = tomlInfo;
198
+ const { include } = tomlInfo.toml;
130
199
  const futureFiles = include.map(g =>
131
200
  glob(g, { cwd: tomlDir, absolute: true }),
132
201
  );
133
202
  const files = (await Promise.all(futureFiles)).flat();
134
203
 
135
- // trigger rebuild on shader file change
136
- files.forEach(f => {
137
- unpluginCtx.addWatchFile(f);
138
- });
204
+ for (const f of files) unpluginCtx.addWatchFile(f);
139
205
 
140
206
  return await loadFiles(files, resolvedRoot);
141
207
  }
142
208
 
143
- /** load a set of shader files, converting to paths relative to the weslRoot directory */
209
+ /** Load shader files, returning paths relative to weslRoot. */
144
210
  async function loadFiles(
145
211
  files: string[],
146
212
  weslRoot: string,
147
213
  ): Promise<Record<string, string>> {
148
- const loaded: [string, string][] = [];
149
-
150
- for (const fullPath of files) {
151
- const data = await fs.readFile(fullPath, "utf-8");
152
- const normalized = data.replace(/\r\n/g, "\n"); // normalize line endings to LF
153
- const relativePath = path.relative(weslRoot, fullPath);
154
- loaded.push([toUnixPath(relativePath), normalized]);
155
- }
156
- return Object.fromEntries(loaded);
214
+ const entries = await Promise.all(
215
+ files.map(async (fullPath): Promise<[string, string]> => {
216
+ const data = await fs.readFile(fullPath, "utf-8");
217
+ const normalized = data.replace(/\r\n/g, "\n"); // normalize line endings to LF
218
+ const key = toUnixPath(path.relative(weslRoot, fullPath));
219
+ return [key, normalized];
220
+ }),
221
+ );
222
+ return Object.fromEntries(entries);
157
223
  }
158
224
 
159
225
  function toUnixPath(p: string): string {
160
- if (path.sep !== "/") {
161
- return p.replaceAll(path.sep, "/");
162
- } else {
163
- return p;
164
- }
226
+ return path.sep !== "/" ? p.replaceAll(path.sep, "/") : p;
165
227
  }
@@ -1,7 +1,7 @@
1
1
  import type { BatchModuleResolver, WeslJsPlugin } from "wesl";
2
2
  import type { WeslTomlInfo } from "wesl-tooling";
3
3
 
4
- /** function type required for for emit extensions */
4
+ /** function type required for emit extensions */
5
5
  export type ExtensionEmitFn = (
6
6
  /** absolute path to the shader to which the extension is attached */
7
7
  shaderPath: string,
@@ -9,8 +9,11 @@ export type ExtensionEmitFn = (
9
9
  /** support functions available to plugin extensions */
10
10
  pluginApi: PluginExtensionApi,
11
11
 
12
- /** static conditions specified on the js import */ // (currently used for ?static)
12
+ /** static conditions specified on the js import */
13
13
  conditions?: Record<string, boolean>,
14
+
15
+ /** plugin-level options from query params (e.g., { include: "all" }) */
16
+ options?: Record<string, string>,
14
17
  ) => Promise<string>;
15
18
 
16
19
  /** an extension that runs inside the wesl-js build plugin */
@@ -23,6 +26,11 @@ export interface PluginExtension extends WeslJsPlugin {
23
26
  emitFn: ExtensionEmitFn;
24
27
  }
25
28
 
29
+ export interface ProjectSources {
30
+ weslSrc: Record<string, string>;
31
+ dependencies: string[];
32
+ }
33
+
26
34
  /** api supplied to plugin extensions */
27
35
  export interface PluginExtensionApi {
28
36
  weslToml: () => Promise<WeslTomlInfo>;
@@ -30,4 +38,15 @@ export interface PluginExtensionApi {
30
38
  weslRegistry: () => Promise<BatchModuleResolver>;
31
39
  weslMain: (baseId: string) => Promise<string>;
32
40
  weslDependencies: () => Promise<string[]>;
41
+ /** weslRoot relative to tomlDir, with forward slashes. */
42
+ debugWeslRoot: () => Promise<string>;
43
+
44
+ /** Get weslSrc scoped to modules reachable from a root, plus their deps. */
45
+ scopedProject: (rootModuleName: string) => Promise<ProjectSources>;
46
+
47
+ /** Fetch project sources, either all or scoped to reachable modules. */
48
+ fetchProject: (
49
+ rootModuleName: string,
50
+ options?: Record<string, string>,
51
+ ) => Promise<ProjectSources>;
33
52
  }