@soda-gql/webpack-plugin 0.11.9 → 0.11.11

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/dist/index.cjs CHANGED
@@ -1,4 +1,5 @@
1
1
  let __soda_gql_builder_plugin_support = require("@soda-gql/builder/plugin-support");
2
+ let node_path = require("node:path");
2
3
  let __soda_gql_builder = require("@soda-gql/builder");
3
4
  let __soda_gql_common = require("@soda-gql/common");
4
5
 
@@ -141,12 +142,19 @@ var SodaGqlWebpackPlugin = class SodaGqlWebpackPlugin {
141
142
  });
142
143
  }
143
144
  /**
145
+ * Convert an absolute file path to a relative path from baseDir.
146
+ */
147
+ toRelativePath(absolutePath) {
148
+ if (!this.pluginSession) return (0, __soda_gql_common.normalizePath)(absolutePath);
149
+ return (0, __soda_gql_common.normalizePath)((0, node_path.relative)(this.pluginSession.config.baseDir, absolutePath));
150
+ }
151
+ /**
144
152
  * Check if a file path corresponds to a soda-gql source file.
145
153
  */
146
154
  isSodaGqlFile(filePath) {
147
155
  if (!this.currentArtifact) return false;
148
- const normalized = (0, __soda_gql_common.normalizePath)(filePath);
149
- for (const element of Object.values(this.currentArtifact.elements)) if ((0, __soda_gql_common.normalizePath)(element.metadata.sourcePath) === normalized) return true;
156
+ const relativePath = this.toRelativePath(filePath);
157
+ for (const element of Object.values(this.currentArtifact.elements)) if ((0, __soda_gql_common.normalizePath)(element.metadata.sourcePath) === relativePath) return true;
150
158
  return false;
151
159
  }
152
160
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../src/plugin.ts"],"sourcesContent":["import type { BuilderArtifact, BuilderArtifactElement } from \"@soda-gql/builder\";\nimport { collectAffectedFiles } from \"@soda-gql/builder\";\nimport {\n createPluginSession,\n getSharedPluginSession,\n getSharedState,\n getStateKey,\n type PluginSession,\n type SwcTransformerInterface,\n setSharedArtifact,\n setSharedPluginSession,\n setSharedSwcTransformer,\n} from \"@soda-gql/builder/plugin-support\";\nimport { normalizePath } from \"@soda-gql/common\";\nimport type { Compiler } from \"webpack\";\nimport type { WebpackPluginOptions } from \"./types\";\n\n/**\n * Webpack plugin for soda-gql that handles incremental rebuilds\n * when model files change during dev server execution.\n */\nexport class SodaGqlWebpackPlugin {\n static readonly pluginName = \"SodaGqlWebpackPlugin\";\n\n private readonly options: WebpackPluginOptions;\n private readonly stateKey: string;\n private pluginSession: PluginSession | null = null;\n private currentArtifact: BuilderArtifact | null = null;\n private previousArtifact: BuilderArtifact | null = null;\n private swcTransformer: SwcTransformerInterface | null = null;\n\n constructor(options: WebpackPluginOptions = {}) {\n this.options = options;\n this.stateKey = getStateKey(options.configPath);\n }\n\n apply(compiler: Compiler): void {\n // Initialize plugin session on first build\n compiler.hooks.beforeRun.tapAsync(SodaGqlWebpackPlugin.pluginName, async (_compiler, callback) => {\n try {\n await this.initialize();\n callback();\n } catch (error) {\n callback(error as Error);\n }\n });\n\n // Handle watch mode\n compiler.hooks.watchRun.tapAsync(SodaGqlWebpackPlugin.pluginName, async (_compiler, callback) => {\n try {\n await this.handleWatchRun();\n callback();\n } catch (error) {\n callback(error as Error);\n }\n });\n\n // Track file invalidations\n compiler.hooks.invalid.tap(SodaGqlWebpackPlugin.pluginName, (fileName, _changeTime) => {\n if (fileName) {\n this.handleFileInvalidation(fileName);\n }\n });\n\n // Cleanup on watch close\n compiler.hooks.watchClose.tap(SodaGqlWebpackPlugin.pluginName, () => {\n this.cleanup();\n });\n }\n\n /**\n * Initialize plugin session and build initial artifact.\n */\n private async initialize(): Promise<void> {\n if (this.pluginSession) return;\n\n // Try to reuse existing shared session (e.g., from client compilation in Next.js)\n const existingSession = getSharedPluginSession(this.stateKey);\n if (existingSession) {\n this.pluginSession = existingSession;\n\n // Still need to build artifact for this compilation\n this.currentArtifact = await this.pluginSession.getArtifactAsync();\n\n // Update shared artifact\n setSharedArtifact(this.stateKey, this.currentArtifact);\n\n // Initialize SWC transformer if configured\n await this.initializeSwcTransformer();\n\n this.log(`Reusing session: ${Object.keys(this.currentArtifact?.elements ?? {}).length} elements`);\n return;\n }\n\n // Fall back to creating new session (first plugin instance)\n this.pluginSession = createPluginSession(this.options, SodaGqlWebpackPlugin.pluginName);\n if (!this.pluginSession) {\n this.log(\"Plugin disabled or config load failed\");\n return;\n }\n\n // Share the plugin session with loader and other plugin instances\n setSharedPluginSession(this.stateKey, this.pluginSession);\n\n // Initial artifact build\n this.currentArtifact = await this.pluginSession.getArtifactAsync();\n\n // Share artifact with loader\n setSharedArtifact(this.stateKey, this.currentArtifact);\n\n // Create SWC transformer if configured\n await this.initializeSwcTransformer();\n\n this.log(`Initial build complete: ${Object.keys(this.currentArtifact?.elements ?? {}).length} elements`);\n }\n\n /**\n * Handle watch mode run - rebuild artifact and compute affected files.\n */\n private async handleWatchRun(): Promise<void> {\n if (!this.pluginSession) {\n await this.initialize();\n }\n\n if (!this.pluginSession) return;\n\n // Store previous artifact for comparison\n this.previousArtifact = this.currentArtifact;\n\n // Rebuild artifact (BuilderService handles change detection internally)\n this.currentArtifact = await this.pluginSession.getArtifactAsync();\n\n // Share artifact with loader\n setSharedArtifact(this.stateKey, this.currentArtifact);\n\n // Reinitialize SWC transformer with new artifact\n await this.initializeSwcTransformer();\n\n if (!this.currentArtifact) {\n this.log(\"Failed to build artifact\");\n return;\n }\n\n // Log artifact changes for debugging (loader handles dependency tracking)\n if (this.previousArtifact && this.hasArtifactChanged()) {\n const changedFiles = this.getChangedSodaGqlFiles();\n const sharedState = getSharedState(this.stateKey);\n const affectedFiles = this.computeAffectedFiles(changedFiles, sharedState.moduleAdjacency);\n\n this.log(`Changed files: ${changedFiles.size}, Affected files: ${affectedFiles.size}`);\n }\n }\n\n /**\n * Handle file invalidation event from webpack.\n */\n private handleFileInvalidation(fileName: string): void {\n const normalized = normalizePath(fileName);\n if (this.isSodaGqlFile(normalized)) {\n this.log(`soda-gql file changed: ${normalized}`);\n }\n }\n\n /**\n * Check if artifact has changed by comparing element counts and hashes.\n */\n private hasArtifactChanged(): boolean {\n if (!this.previousArtifact || !this.currentArtifact) return true;\n\n const prevCount = Object.keys(this.previousArtifact.elements).length;\n const newCount = Object.keys(this.currentArtifact.elements).length;\n if (prevCount !== newCount) return true;\n\n // Compare individual elements by their content hash\n const prevElements = this.previousArtifact.elements as Record<string, BuilderArtifactElement>;\n const currElements = this.currentArtifact.elements as Record<string, BuilderArtifactElement>;\n\n for (const [id, element] of Object.entries(currElements)) {\n const prevElement = prevElements[id];\n if (!prevElement) return true;\n // Compare using metadata\n if (element.metadata.contentHash !== prevElement.metadata.contentHash) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Get files that changed between previous and current artifact.\n */\n private getChangedSodaGqlFiles(): Set<string> {\n const changed = new Set<string>();\n\n if (!this.previousArtifact || !this.currentArtifact) return changed;\n\n const prevElements = this.previousArtifact.elements as Record<string, BuilderArtifactElement>;\n const currElements = this.currentArtifact.elements as Record<string, BuilderArtifactElement>;\n\n // Compare elements by their source paths and content hashes\n for (const [id, element] of Object.entries(currElements)) {\n const prevElement = prevElements[id];\n const sourcePath = element.metadata.sourcePath;\n\n if (!prevElement || prevElement.metadata.contentHash !== element.metadata.contentHash) {\n changed.add(normalizePath(sourcePath));\n }\n }\n\n // Check for removed elements\n for (const [id, element] of Object.entries(prevElements)) {\n if (!currElements[id]) {\n const sourcePath = element.metadata.sourcePath;\n changed.add(normalizePath(sourcePath));\n }\n }\n\n return changed;\n }\n\n /**\n * Compute all files affected by the changed files using module adjacency.\n */\n private computeAffectedFiles(changedFiles: Set<string>, moduleAdjacency: Map<string, Set<string>>): Set<string> {\n // Use the existing collectAffectedFiles from builder\n return collectAffectedFiles({\n changedFiles,\n removedFiles: new Set(),\n previousModuleAdjacency: moduleAdjacency,\n });\n }\n\n /**\n * Check if a file path corresponds to a soda-gql source file.\n */\n private isSodaGqlFile(filePath: string): boolean {\n if (!this.currentArtifact) return false;\n\n const normalized = normalizePath(filePath);\n for (const element of Object.values(this.currentArtifact.elements)) {\n if (normalizePath(element.metadata.sourcePath) === normalized) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Initialize SWC transformer if configured.\n * Creates a new transformer instance with the current artifact.\n */\n private async initializeSwcTransformer(): Promise<void> {\n if (this.options.transformer !== \"swc\") {\n return;\n }\n\n if (!this.currentArtifact || !this.pluginSession) {\n this.swcTransformer = null;\n setSharedSwcTransformer(this.stateKey, null);\n return;\n }\n\n try {\n const { createTransformer } = await import(\"@soda-gql/swc\");\n this.swcTransformer = await createTransformer({\n config: this.pluginSession.config,\n artifact: this.currentArtifact,\n sourceMap: true,\n });\n setSharedSwcTransformer(this.stateKey, this.swcTransformer);\n this.log(\"SWC transformer initialized\");\n } catch (error) {\n console.warn(\n `[@soda-gql/webpack-plugin] Failed to initialize SWC transformer: ${error}. Make sure @soda-gql/swc is installed.`,\n );\n this.swcTransformer = null;\n setSharedSwcTransformer(this.stateKey, null);\n }\n }\n\n /**\n * Cleanup resources.\n */\n private cleanup(): void {\n this.pluginSession = null;\n this.currentArtifact = null;\n this.previousArtifact = null;\n this.swcTransformer = null;\n setSharedPluginSession(this.stateKey, null);\n setSharedArtifact(this.stateKey, null);\n setSharedSwcTransformer(this.stateKey, null);\n }\n\n /**\n * Log a message if debug mode is enabled.\n */\n private log(message: string): void {\n if (this.options.debug) {\n console.log(`[${SodaGqlWebpackPlugin.pluginName}] ${message}`);\n }\n }\n\n /**\n * Get the current artifact (for use by loader).\n */\n getArtifact(): BuilderArtifact | null {\n return this.currentArtifact;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/plugin.ts"],"sourcesContent":["import { relative } from \"node:path\";\nimport type { BuilderArtifact, BuilderArtifactElement } from \"@soda-gql/builder\";\nimport { collectAffectedFiles } from \"@soda-gql/builder\";\nimport {\n createPluginSession,\n getSharedPluginSession,\n getSharedState,\n getStateKey,\n type PluginSession,\n type SwcTransformerInterface,\n setSharedArtifact,\n setSharedPluginSession,\n setSharedSwcTransformer,\n} from \"@soda-gql/builder/plugin-support\";\nimport { normalizePath } from \"@soda-gql/common\";\nimport type { Compiler } from \"webpack\";\nimport type { WebpackPluginOptions } from \"./types\";\n\n/**\n * Webpack plugin for soda-gql that handles incremental rebuilds\n * when model files change during dev server execution.\n */\nexport class SodaGqlWebpackPlugin {\n static readonly pluginName = \"SodaGqlWebpackPlugin\";\n\n private readonly options: WebpackPluginOptions;\n private readonly stateKey: string;\n private pluginSession: PluginSession | null = null;\n private currentArtifact: BuilderArtifact | null = null;\n private previousArtifact: BuilderArtifact | null = null;\n private swcTransformer: SwcTransformerInterface | null = null;\n\n constructor(options: WebpackPluginOptions = {}) {\n this.options = options;\n this.stateKey = getStateKey(options.configPath);\n }\n\n apply(compiler: Compiler): void {\n // Initialize plugin session on first build\n compiler.hooks.beforeRun.tapAsync(SodaGqlWebpackPlugin.pluginName, async (_compiler, callback) => {\n try {\n await this.initialize();\n callback();\n } catch (error) {\n callback(error as Error);\n }\n });\n\n // Handle watch mode\n compiler.hooks.watchRun.tapAsync(SodaGqlWebpackPlugin.pluginName, async (_compiler, callback) => {\n try {\n await this.handleWatchRun();\n callback();\n } catch (error) {\n callback(error as Error);\n }\n });\n\n // Track file invalidations\n compiler.hooks.invalid.tap(SodaGqlWebpackPlugin.pluginName, (fileName, _changeTime) => {\n if (fileName) {\n this.handleFileInvalidation(fileName);\n }\n });\n\n // Cleanup on watch close\n compiler.hooks.watchClose.tap(SodaGqlWebpackPlugin.pluginName, () => {\n this.cleanup();\n });\n }\n\n /**\n * Initialize plugin session and build initial artifact.\n */\n private async initialize(): Promise<void> {\n if (this.pluginSession) return;\n\n // Try to reuse existing shared session (e.g., from client compilation in Next.js)\n const existingSession = getSharedPluginSession(this.stateKey);\n if (existingSession) {\n this.pluginSession = existingSession;\n\n // Still need to build artifact for this compilation\n this.currentArtifact = await this.pluginSession.getArtifactAsync();\n\n // Update shared artifact\n setSharedArtifact(this.stateKey, this.currentArtifact);\n\n // Initialize SWC transformer if configured\n await this.initializeSwcTransformer();\n\n this.log(`Reusing session: ${Object.keys(this.currentArtifact?.elements ?? {}).length} elements`);\n return;\n }\n\n // Fall back to creating new session (first plugin instance)\n this.pluginSession = createPluginSession(this.options, SodaGqlWebpackPlugin.pluginName);\n if (!this.pluginSession) {\n this.log(\"Plugin disabled or config load failed\");\n return;\n }\n\n // Share the plugin session with loader and other plugin instances\n setSharedPluginSession(this.stateKey, this.pluginSession);\n\n // Initial artifact build\n this.currentArtifact = await this.pluginSession.getArtifactAsync();\n\n // Share artifact with loader\n setSharedArtifact(this.stateKey, this.currentArtifact);\n\n // Create SWC transformer if configured\n await this.initializeSwcTransformer();\n\n this.log(`Initial build complete: ${Object.keys(this.currentArtifact?.elements ?? {}).length} elements`);\n }\n\n /**\n * Handle watch mode run - rebuild artifact and compute affected files.\n */\n private async handleWatchRun(): Promise<void> {\n if (!this.pluginSession) {\n await this.initialize();\n }\n\n if (!this.pluginSession) return;\n\n // Store previous artifact for comparison\n this.previousArtifact = this.currentArtifact;\n\n // Rebuild artifact (BuilderService handles change detection internally)\n this.currentArtifact = await this.pluginSession.getArtifactAsync();\n\n // Share artifact with loader\n setSharedArtifact(this.stateKey, this.currentArtifact);\n\n // Reinitialize SWC transformer with new artifact\n await this.initializeSwcTransformer();\n\n if (!this.currentArtifact) {\n this.log(\"Failed to build artifact\");\n return;\n }\n\n // Log artifact changes for debugging (loader handles dependency tracking)\n if (this.previousArtifact && this.hasArtifactChanged()) {\n const changedFiles = this.getChangedSodaGqlFiles();\n const sharedState = getSharedState(this.stateKey);\n const affectedFiles = this.computeAffectedFiles(changedFiles, sharedState.moduleAdjacency);\n\n this.log(`Changed files: ${changedFiles.size}, Affected files: ${affectedFiles.size}`);\n }\n }\n\n /**\n * Handle file invalidation event from webpack.\n */\n private handleFileInvalidation(fileName: string): void {\n const normalized = normalizePath(fileName);\n if (this.isSodaGqlFile(normalized)) {\n this.log(`soda-gql file changed: ${normalized}`);\n }\n }\n\n /**\n * Check if artifact has changed by comparing element counts and hashes.\n */\n private hasArtifactChanged(): boolean {\n if (!this.previousArtifact || !this.currentArtifact) return true;\n\n const prevCount = Object.keys(this.previousArtifact.elements).length;\n const newCount = Object.keys(this.currentArtifact.elements).length;\n if (prevCount !== newCount) return true;\n\n // Compare individual elements by their content hash\n const prevElements = this.previousArtifact.elements as Record<string, BuilderArtifactElement>;\n const currElements = this.currentArtifact.elements as Record<string, BuilderArtifactElement>;\n\n for (const [id, element] of Object.entries(currElements)) {\n const prevElement = prevElements[id];\n if (!prevElement) return true;\n // Compare using metadata\n if (element.metadata.contentHash !== prevElement.metadata.contentHash) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Get files that changed between previous and current artifact.\n */\n private getChangedSodaGqlFiles(): Set<string> {\n const changed = new Set<string>();\n\n if (!this.previousArtifact || !this.currentArtifact) return changed;\n\n const prevElements = this.previousArtifact.elements as Record<string, BuilderArtifactElement>;\n const currElements = this.currentArtifact.elements as Record<string, BuilderArtifactElement>;\n\n // Compare elements by their source paths and content hashes\n for (const [id, element] of Object.entries(currElements)) {\n const prevElement = prevElements[id];\n const sourcePath = element.metadata.sourcePath;\n\n if (!prevElement || prevElement.metadata.contentHash !== element.metadata.contentHash) {\n changed.add(normalizePath(sourcePath));\n }\n }\n\n // Check for removed elements\n for (const [id, element] of Object.entries(prevElements)) {\n if (!currElements[id]) {\n const sourcePath = element.metadata.sourcePath;\n changed.add(normalizePath(sourcePath));\n }\n }\n\n return changed;\n }\n\n /**\n * Compute all files affected by the changed files using module adjacency.\n */\n private computeAffectedFiles(changedFiles: Set<string>, moduleAdjacency: Map<string, Set<string>>): Set<string> {\n // Use the existing collectAffectedFiles from builder\n return collectAffectedFiles({\n changedFiles,\n removedFiles: new Set(),\n previousModuleAdjacency: moduleAdjacency,\n });\n }\n\n /**\n * Convert an absolute file path to a relative path from baseDir.\n */\n private toRelativePath(absolutePath: string): string {\n if (!this.pluginSession) {\n return normalizePath(absolutePath);\n }\n return normalizePath(relative(this.pluginSession.config.baseDir, absolutePath));\n }\n\n /**\n * Check if a file path corresponds to a soda-gql source file.\n */\n private isSodaGqlFile(filePath: string): boolean {\n if (!this.currentArtifact) return false;\n\n // Convert absolute path to relative for matching against artifact sourcePaths\n const relativePath = this.toRelativePath(filePath);\n for (const element of Object.values(this.currentArtifact.elements)) {\n if (normalizePath(element.metadata.sourcePath) === relativePath) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Initialize SWC transformer if configured.\n * Creates a new transformer instance with the current artifact.\n */\n private async initializeSwcTransformer(): Promise<void> {\n if (this.options.transformer !== \"swc\") {\n return;\n }\n\n if (!this.currentArtifact || !this.pluginSession) {\n this.swcTransformer = null;\n setSharedSwcTransformer(this.stateKey, null);\n return;\n }\n\n try {\n const { createTransformer } = await import(\"@soda-gql/swc\");\n this.swcTransformer = await createTransformer({\n config: this.pluginSession.config,\n artifact: this.currentArtifact,\n sourceMap: true,\n });\n setSharedSwcTransformer(this.stateKey, this.swcTransformer);\n this.log(\"SWC transformer initialized\");\n } catch (error) {\n console.warn(\n `[@soda-gql/webpack-plugin] Failed to initialize SWC transformer: ${error}. Make sure @soda-gql/swc is installed.`,\n );\n this.swcTransformer = null;\n setSharedSwcTransformer(this.stateKey, null);\n }\n }\n\n /**\n * Cleanup resources.\n */\n private cleanup(): void {\n this.pluginSession = null;\n this.currentArtifact = null;\n this.previousArtifact = null;\n this.swcTransformer = null;\n setSharedPluginSession(this.stateKey, null);\n setSharedArtifact(this.stateKey, null);\n setSharedSwcTransformer(this.stateKey, null);\n }\n\n /**\n * Log a message if debug mode is enabled.\n */\n private log(message: string): void {\n if (this.options.debug) {\n console.log(`[${SodaGqlWebpackPlugin.pluginName}] ${message}`);\n }\n }\n\n /**\n * Get the current artifact (for use by loader).\n */\n getArtifact(): BuilderArtifact | null {\n return this.currentArtifact;\n }\n}\n"],"mappings":"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"}
package/dist/index.d.cts CHANGED
@@ -43,6 +43,10 @@ declare class SodaGqlWebpackPlugin {
43
43
  * Compute all files affected by the changed files using module adjacency.
44
44
  */
45
45
  private computeAffectedFiles;
46
+ /**
47
+ * Convert an absolute file path to a relative path from baseDir.
48
+ */
49
+ private toRelativePath;
46
50
  /**
47
51
  * Check if a file path corresponds to a soda-gql source file.
48
52
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/plugin.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAqBA;AAUuB,cAVV,oBAAA,CAUU;EAKL,gBAAA,UAAA,GAAA,sBAAA;EA8QD,iBAAA,OAAA;EAAe,iBAAA,QAAA;;;;;wBAnRT;kBAKL;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA8QD"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/plugin.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAsBA;AAUuB,cAVV,oBAAA,CAUU;EAKL,gBAAA,UAAA,GAAA,sBAAA;EAyRD,iBAAA,OAAA;EAAe,iBAAA,QAAA;;;;;wBA9RT;kBAKL;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAyRD"}
package/dist/index.d.mts CHANGED
@@ -43,6 +43,10 @@ declare class SodaGqlWebpackPlugin {
43
43
  * Compute all files affected by the changed files using module adjacency.
44
44
  */
45
45
  private computeAffectedFiles;
46
+ /**
47
+ * Convert an absolute file path to a relative path from baseDir.
48
+ */
49
+ private toRelativePath;
46
50
  /**
47
51
  * Check if a file path corresponds to a soda-gql source file.
48
52
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/plugin.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAqBA;AAUuB,cAVV,oBAAA,CAUU;EAKL,gBAAA,UAAA,GAAA,sBAAA;EA8QD,iBAAA,OAAA;EAAe,iBAAA,QAAA;;;;;wBAnRT;kBAKL;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA8QD"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/plugin.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAsBA;AAUuB,cAVV,oBAAA,CAUU;EAKL,gBAAA,UAAA,GAAA,sBAAA;EAyRD,iBAAA,OAAA;EAAe,iBAAA,QAAA;;;;;wBA9RT;kBAKL;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAyRD"}
package/dist/index.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  import { createPluginSession, getSharedArtifact, getSharedBuilderService, getSharedPluginSession, getSharedPluginSession as getSharedPluginSession$1, getSharedState, getSharedState as getSharedState$1, getStateKey, getStateKey as getStateKey$1, setSharedArtifact, setSharedBuilderService, setSharedPluginSession, setSharedPluginSession as setSharedPluginSession$1, setSharedSwcTransformer } from "@soda-gql/builder/plugin-support";
2
+ import { relative } from "node:path";
2
3
  import { collectAffectedFiles } from "@soda-gql/builder";
3
4
  import { normalizePath } from "@soda-gql/common";
4
5
 
@@ -141,12 +142,19 @@ var SodaGqlWebpackPlugin = class SodaGqlWebpackPlugin {
141
142
  });
142
143
  }
143
144
  /**
145
+ * Convert an absolute file path to a relative path from baseDir.
146
+ */
147
+ toRelativePath(absolutePath) {
148
+ if (!this.pluginSession) return normalizePath(absolutePath);
149
+ return normalizePath(relative(this.pluginSession.config.baseDir, absolutePath));
150
+ }
151
+ /**
144
152
  * Check if a file path corresponds to a soda-gql source file.
145
153
  */
146
154
  isSodaGqlFile(filePath) {
147
155
  if (!this.currentArtifact) return false;
148
- const normalized = normalizePath(filePath);
149
- for (const element of Object.values(this.currentArtifact.elements)) if (normalizePath(element.metadata.sourcePath) === normalized) return true;
156
+ const relativePath = this.toRelativePath(filePath);
157
+ for (const element of Object.values(this.currentArtifact.elements)) if (normalizePath(element.metadata.sourcePath) === relativePath) return true;
150
158
  return false;
151
159
  }
152
160
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["getStateKey","getSharedPluginSession","getSharedState"],"sources":["../src/plugin.ts"],"sourcesContent":["import type { BuilderArtifact, BuilderArtifactElement } from \"@soda-gql/builder\";\nimport { collectAffectedFiles } from \"@soda-gql/builder\";\nimport {\n createPluginSession,\n getSharedPluginSession,\n getSharedState,\n getStateKey,\n type PluginSession,\n type SwcTransformerInterface,\n setSharedArtifact,\n setSharedPluginSession,\n setSharedSwcTransformer,\n} from \"@soda-gql/builder/plugin-support\";\nimport { normalizePath } from \"@soda-gql/common\";\nimport type { Compiler } from \"webpack\";\nimport type { WebpackPluginOptions } from \"./types\";\n\n/**\n * Webpack plugin for soda-gql that handles incremental rebuilds\n * when model files change during dev server execution.\n */\nexport class SodaGqlWebpackPlugin {\n static readonly pluginName = \"SodaGqlWebpackPlugin\";\n\n private readonly options: WebpackPluginOptions;\n private readonly stateKey: string;\n private pluginSession: PluginSession | null = null;\n private currentArtifact: BuilderArtifact | null = null;\n private previousArtifact: BuilderArtifact | null = null;\n private swcTransformer: SwcTransformerInterface | null = null;\n\n constructor(options: WebpackPluginOptions = {}) {\n this.options = options;\n this.stateKey = getStateKey(options.configPath);\n }\n\n apply(compiler: Compiler): void {\n // Initialize plugin session on first build\n compiler.hooks.beforeRun.tapAsync(SodaGqlWebpackPlugin.pluginName, async (_compiler, callback) => {\n try {\n await this.initialize();\n callback();\n } catch (error) {\n callback(error as Error);\n }\n });\n\n // Handle watch mode\n compiler.hooks.watchRun.tapAsync(SodaGqlWebpackPlugin.pluginName, async (_compiler, callback) => {\n try {\n await this.handleWatchRun();\n callback();\n } catch (error) {\n callback(error as Error);\n }\n });\n\n // Track file invalidations\n compiler.hooks.invalid.tap(SodaGqlWebpackPlugin.pluginName, (fileName, _changeTime) => {\n if (fileName) {\n this.handleFileInvalidation(fileName);\n }\n });\n\n // Cleanup on watch close\n compiler.hooks.watchClose.tap(SodaGqlWebpackPlugin.pluginName, () => {\n this.cleanup();\n });\n }\n\n /**\n * Initialize plugin session and build initial artifact.\n */\n private async initialize(): Promise<void> {\n if (this.pluginSession) return;\n\n // Try to reuse existing shared session (e.g., from client compilation in Next.js)\n const existingSession = getSharedPluginSession(this.stateKey);\n if (existingSession) {\n this.pluginSession = existingSession;\n\n // Still need to build artifact for this compilation\n this.currentArtifact = await this.pluginSession.getArtifactAsync();\n\n // Update shared artifact\n setSharedArtifact(this.stateKey, this.currentArtifact);\n\n // Initialize SWC transformer if configured\n await this.initializeSwcTransformer();\n\n this.log(`Reusing session: ${Object.keys(this.currentArtifact?.elements ?? {}).length} elements`);\n return;\n }\n\n // Fall back to creating new session (first plugin instance)\n this.pluginSession = createPluginSession(this.options, SodaGqlWebpackPlugin.pluginName);\n if (!this.pluginSession) {\n this.log(\"Plugin disabled or config load failed\");\n return;\n }\n\n // Share the plugin session with loader and other plugin instances\n setSharedPluginSession(this.stateKey, this.pluginSession);\n\n // Initial artifact build\n this.currentArtifact = await this.pluginSession.getArtifactAsync();\n\n // Share artifact with loader\n setSharedArtifact(this.stateKey, this.currentArtifact);\n\n // Create SWC transformer if configured\n await this.initializeSwcTransformer();\n\n this.log(`Initial build complete: ${Object.keys(this.currentArtifact?.elements ?? {}).length} elements`);\n }\n\n /**\n * Handle watch mode run - rebuild artifact and compute affected files.\n */\n private async handleWatchRun(): Promise<void> {\n if (!this.pluginSession) {\n await this.initialize();\n }\n\n if (!this.pluginSession) return;\n\n // Store previous artifact for comparison\n this.previousArtifact = this.currentArtifact;\n\n // Rebuild artifact (BuilderService handles change detection internally)\n this.currentArtifact = await this.pluginSession.getArtifactAsync();\n\n // Share artifact with loader\n setSharedArtifact(this.stateKey, this.currentArtifact);\n\n // Reinitialize SWC transformer with new artifact\n await this.initializeSwcTransformer();\n\n if (!this.currentArtifact) {\n this.log(\"Failed to build artifact\");\n return;\n }\n\n // Log artifact changes for debugging (loader handles dependency tracking)\n if (this.previousArtifact && this.hasArtifactChanged()) {\n const changedFiles = this.getChangedSodaGqlFiles();\n const sharedState = getSharedState(this.stateKey);\n const affectedFiles = this.computeAffectedFiles(changedFiles, sharedState.moduleAdjacency);\n\n this.log(`Changed files: ${changedFiles.size}, Affected files: ${affectedFiles.size}`);\n }\n }\n\n /**\n * Handle file invalidation event from webpack.\n */\n private handleFileInvalidation(fileName: string): void {\n const normalized = normalizePath(fileName);\n if (this.isSodaGqlFile(normalized)) {\n this.log(`soda-gql file changed: ${normalized}`);\n }\n }\n\n /**\n * Check if artifact has changed by comparing element counts and hashes.\n */\n private hasArtifactChanged(): boolean {\n if (!this.previousArtifact || !this.currentArtifact) return true;\n\n const prevCount = Object.keys(this.previousArtifact.elements).length;\n const newCount = Object.keys(this.currentArtifact.elements).length;\n if (prevCount !== newCount) return true;\n\n // Compare individual elements by their content hash\n const prevElements = this.previousArtifact.elements as Record<string, BuilderArtifactElement>;\n const currElements = this.currentArtifact.elements as Record<string, BuilderArtifactElement>;\n\n for (const [id, element] of Object.entries(currElements)) {\n const prevElement = prevElements[id];\n if (!prevElement) return true;\n // Compare using metadata\n if (element.metadata.contentHash !== prevElement.metadata.contentHash) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Get files that changed between previous and current artifact.\n */\n private getChangedSodaGqlFiles(): Set<string> {\n const changed = new Set<string>();\n\n if (!this.previousArtifact || !this.currentArtifact) return changed;\n\n const prevElements = this.previousArtifact.elements as Record<string, BuilderArtifactElement>;\n const currElements = this.currentArtifact.elements as Record<string, BuilderArtifactElement>;\n\n // Compare elements by their source paths and content hashes\n for (const [id, element] of Object.entries(currElements)) {\n const prevElement = prevElements[id];\n const sourcePath = element.metadata.sourcePath;\n\n if (!prevElement || prevElement.metadata.contentHash !== element.metadata.contentHash) {\n changed.add(normalizePath(sourcePath));\n }\n }\n\n // Check for removed elements\n for (const [id, element] of Object.entries(prevElements)) {\n if (!currElements[id]) {\n const sourcePath = element.metadata.sourcePath;\n changed.add(normalizePath(sourcePath));\n }\n }\n\n return changed;\n }\n\n /**\n * Compute all files affected by the changed files using module adjacency.\n */\n private computeAffectedFiles(changedFiles: Set<string>, moduleAdjacency: Map<string, Set<string>>): Set<string> {\n // Use the existing collectAffectedFiles from builder\n return collectAffectedFiles({\n changedFiles,\n removedFiles: new Set(),\n previousModuleAdjacency: moduleAdjacency,\n });\n }\n\n /**\n * Check if a file path corresponds to a soda-gql source file.\n */\n private isSodaGqlFile(filePath: string): boolean {\n if (!this.currentArtifact) return false;\n\n const normalized = normalizePath(filePath);\n for (const element of Object.values(this.currentArtifact.elements)) {\n if (normalizePath(element.metadata.sourcePath) === normalized) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Initialize SWC transformer if configured.\n * Creates a new transformer instance with the current artifact.\n */\n private async initializeSwcTransformer(): Promise<void> {\n if (this.options.transformer !== \"swc\") {\n return;\n }\n\n if (!this.currentArtifact || !this.pluginSession) {\n this.swcTransformer = null;\n setSharedSwcTransformer(this.stateKey, null);\n return;\n }\n\n try {\n const { createTransformer } = await import(\"@soda-gql/swc\");\n this.swcTransformer = await createTransformer({\n config: this.pluginSession.config,\n artifact: this.currentArtifact,\n sourceMap: true,\n });\n setSharedSwcTransformer(this.stateKey, this.swcTransformer);\n this.log(\"SWC transformer initialized\");\n } catch (error) {\n console.warn(\n `[@soda-gql/webpack-plugin] Failed to initialize SWC transformer: ${error}. Make sure @soda-gql/swc is installed.`,\n );\n this.swcTransformer = null;\n setSharedSwcTransformer(this.stateKey, null);\n }\n }\n\n /**\n * Cleanup resources.\n */\n private cleanup(): void {\n this.pluginSession = null;\n this.currentArtifact = null;\n this.previousArtifact = null;\n this.swcTransformer = null;\n setSharedPluginSession(this.stateKey, null);\n setSharedArtifact(this.stateKey, null);\n setSharedSwcTransformer(this.stateKey, null);\n }\n\n /**\n * Log a message if debug mode is enabled.\n */\n private log(message: string): void {\n if (this.options.debug) {\n console.log(`[${SodaGqlWebpackPlugin.pluginName}] ${message}`);\n }\n }\n\n /**\n * Get the current artifact (for use by loader).\n */\n getArtifact(): BuilderArtifact | null {\n return this.currentArtifact;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["getStateKey","getSharedPluginSession","getSharedState"],"sources":["../src/plugin.ts"],"sourcesContent":["import { relative } from \"node:path\";\nimport type { BuilderArtifact, BuilderArtifactElement } from \"@soda-gql/builder\";\nimport { collectAffectedFiles } from \"@soda-gql/builder\";\nimport {\n createPluginSession,\n getSharedPluginSession,\n getSharedState,\n getStateKey,\n type PluginSession,\n type SwcTransformerInterface,\n setSharedArtifact,\n setSharedPluginSession,\n setSharedSwcTransformer,\n} from \"@soda-gql/builder/plugin-support\";\nimport { normalizePath } from \"@soda-gql/common\";\nimport type { Compiler } from \"webpack\";\nimport type { WebpackPluginOptions } from \"./types\";\n\n/**\n * Webpack plugin for soda-gql that handles incremental rebuilds\n * when model files change during dev server execution.\n */\nexport class SodaGqlWebpackPlugin {\n static readonly pluginName = \"SodaGqlWebpackPlugin\";\n\n private readonly options: WebpackPluginOptions;\n private readonly stateKey: string;\n private pluginSession: PluginSession | null = null;\n private currentArtifact: BuilderArtifact | null = null;\n private previousArtifact: BuilderArtifact | null = null;\n private swcTransformer: SwcTransformerInterface | null = null;\n\n constructor(options: WebpackPluginOptions = {}) {\n this.options = options;\n this.stateKey = getStateKey(options.configPath);\n }\n\n apply(compiler: Compiler): void {\n // Initialize plugin session on first build\n compiler.hooks.beforeRun.tapAsync(SodaGqlWebpackPlugin.pluginName, async (_compiler, callback) => {\n try {\n await this.initialize();\n callback();\n } catch (error) {\n callback(error as Error);\n }\n });\n\n // Handle watch mode\n compiler.hooks.watchRun.tapAsync(SodaGqlWebpackPlugin.pluginName, async (_compiler, callback) => {\n try {\n await this.handleWatchRun();\n callback();\n } catch (error) {\n callback(error as Error);\n }\n });\n\n // Track file invalidations\n compiler.hooks.invalid.tap(SodaGqlWebpackPlugin.pluginName, (fileName, _changeTime) => {\n if (fileName) {\n this.handleFileInvalidation(fileName);\n }\n });\n\n // Cleanup on watch close\n compiler.hooks.watchClose.tap(SodaGqlWebpackPlugin.pluginName, () => {\n this.cleanup();\n });\n }\n\n /**\n * Initialize plugin session and build initial artifact.\n */\n private async initialize(): Promise<void> {\n if (this.pluginSession) return;\n\n // Try to reuse existing shared session (e.g., from client compilation in Next.js)\n const existingSession = getSharedPluginSession(this.stateKey);\n if (existingSession) {\n this.pluginSession = existingSession;\n\n // Still need to build artifact for this compilation\n this.currentArtifact = await this.pluginSession.getArtifactAsync();\n\n // Update shared artifact\n setSharedArtifact(this.stateKey, this.currentArtifact);\n\n // Initialize SWC transformer if configured\n await this.initializeSwcTransformer();\n\n this.log(`Reusing session: ${Object.keys(this.currentArtifact?.elements ?? {}).length} elements`);\n return;\n }\n\n // Fall back to creating new session (first plugin instance)\n this.pluginSession = createPluginSession(this.options, SodaGqlWebpackPlugin.pluginName);\n if (!this.pluginSession) {\n this.log(\"Plugin disabled or config load failed\");\n return;\n }\n\n // Share the plugin session with loader and other plugin instances\n setSharedPluginSession(this.stateKey, this.pluginSession);\n\n // Initial artifact build\n this.currentArtifact = await this.pluginSession.getArtifactAsync();\n\n // Share artifact with loader\n setSharedArtifact(this.stateKey, this.currentArtifact);\n\n // Create SWC transformer if configured\n await this.initializeSwcTransformer();\n\n this.log(`Initial build complete: ${Object.keys(this.currentArtifact?.elements ?? {}).length} elements`);\n }\n\n /**\n * Handle watch mode run - rebuild artifact and compute affected files.\n */\n private async handleWatchRun(): Promise<void> {\n if (!this.pluginSession) {\n await this.initialize();\n }\n\n if (!this.pluginSession) return;\n\n // Store previous artifact for comparison\n this.previousArtifact = this.currentArtifact;\n\n // Rebuild artifact (BuilderService handles change detection internally)\n this.currentArtifact = await this.pluginSession.getArtifactAsync();\n\n // Share artifact with loader\n setSharedArtifact(this.stateKey, this.currentArtifact);\n\n // Reinitialize SWC transformer with new artifact\n await this.initializeSwcTransformer();\n\n if (!this.currentArtifact) {\n this.log(\"Failed to build artifact\");\n return;\n }\n\n // Log artifact changes for debugging (loader handles dependency tracking)\n if (this.previousArtifact && this.hasArtifactChanged()) {\n const changedFiles = this.getChangedSodaGqlFiles();\n const sharedState = getSharedState(this.stateKey);\n const affectedFiles = this.computeAffectedFiles(changedFiles, sharedState.moduleAdjacency);\n\n this.log(`Changed files: ${changedFiles.size}, Affected files: ${affectedFiles.size}`);\n }\n }\n\n /**\n * Handle file invalidation event from webpack.\n */\n private handleFileInvalidation(fileName: string): void {\n const normalized = normalizePath(fileName);\n if (this.isSodaGqlFile(normalized)) {\n this.log(`soda-gql file changed: ${normalized}`);\n }\n }\n\n /**\n * Check if artifact has changed by comparing element counts and hashes.\n */\n private hasArtifactChanged(): boolean {\n if (!this.previousArtifact || !this.currentArtifact) return true;\n\n const prevCount = Object.keys(this.previousArtifact.elements).length;\n const newCount = Object.keys(this.currentArtifact.elements).length;\n if (prevCount !== newCount) return true;\n\n // Compare individual elements by their content hash\n const prevElements = this.previousArtifact.elements as Record<string, BuilderArtifactElement>;\n const currElements = this.currentArtifact.elements as Record<string, BuilderArtifactElement>;\n\n for (const [id, element] of Object.entries(currElements)) {\n const prevElement = prevElements[id];\n if (!prevElement) return true;\n // Compare using metadata\n if (element.metadata.contentHash !== prevElement.metadata.contentHash) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Get files that changed between previous and current artifact.\n */\n private getChangedSodaGqlFiles(): Set<string> {\n const changed = new Set<string>();\n\n if (!this.previousArtifact || !this.currentArtifact) return changed;\n\n const prevElements = this.previousArtifact.elements as Record<string, BuilderArtifactElement>;\n const currElements = this.currentArtifact.elements as Record<string, BuilderArtifactElement>;\n\n // Compare elements by their source paths and content hashes\n for (const [id, element] of Object.entries(currElements)) {\n const prevElement = prevElements[id];\n const sourcePath = element.metadata.sourcePath;\n\n if (!prevElement || prevElement.metadata.contentHash !== element.metadata.contentHash) {\n changed.add(normalizePath(sourcePath));\n }\n }\n\n // Check for removed elements\n for (const [id, element] of Object.entries(prevElements)) {\n if (!currElements[id]) {\n const sourcePath = element.metadata.sourcePath;\n changed.add(normalizePath(sourcePath));\n }\n }\n\n return changed;\n }\n\n /**\n * Compute all files affected by the changed files using module adjacency.\n */\n private computeAffectedFiles(changedFiles: Set<string>, moduleAdjacency: Map<string, Set<string>>): Set<string> {\n // Use the existing collectAffectedFiles from builder\n return collectAffectedFiles({\n changedFiles,\n removedFiles: new Set(),\n previousModuleAdjacency: moduleAdjacency,\n });\n }\n\n /**\n * Convert an absolute file path to a relative path from baseDir.\n */\n private toRelativePath(absolutePath: string): string {\n if (!this.pluginSession) {\n return normalizePath(absolutePath);\n }\n return normalizePath(relative(this.pluginSession.config.baseDir, absolutePath));\n }\n\n /**\n * Check if a file path corresponds to a soda-gql source file.\n */\n private isSodaGqlFile(filePath: string): boolean {\n if (!this.currentArtifact) return false;\n\n // Convert absolute path to relative for matching against artifact sourcePaths\n const relativePath = this.toRelativePath(filePath);\n for (const element of Object.values(this.currentArtifact.elements)) {\n if (normalizePath(element.metadata.sourcePath) === relativePath) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Initialize SWC transformer if configured.\n * Creates a new transformer instance with the current artifact.\n */\n private async initializeSwcTransformer(): Promise<void> {\n if (this.options.transformer !== \"swc\") {\n return;\n }\n\n if (!this.currentArtifact || !this.pluginSession) {\n this.swcTransformer = null;\n setSharedSwcTransformer(this.stateKey, null);\n return;\n }\n\n try {\n const { createTransformer } = await import(\"@soda-gql/swc\");\n this.swcTransformer = await createTransformer({\n config: this.pluginSession.config,\n artifact: this.currentArtifact,\n sourceMap: true,\n });\n setSharedSwcTransformer(this.stateKey, this.swcTransformer);\n this.log(\"SWC transformer initialized\");\n } catch (error) {\n console.warn(\n `[@soda-gql/webpack-plugin] Failed to initialize SWC transformer: ${error}. Make sure @soda-gql/swc is installed.`,\n );\n this.swcTransformer = null;\n setSharedSwcTransformer(this.stateKey, null);\n }\n }\n\n /**\n * Cleanup resources.\n */\n private cleanup(): void {\n this.pluginSession = null;\n this.currentArtifact = null;\n this.previousArtifact = null;\n this.swcTransformer = null;\n setSharedPluginSession(this.stateKey, null);\n setSharedArtifact(this.stateKey, null);\n setSharedSwcTransformer(this.stateKey, null);\n }\n\n /**\n * Log a message if debug mode is enabled.\n */\n private log(message: string): void {\n if (this.options.debug) {\n console.log(`[${SodaGqlWebpackPlugin.pluginName}] ${message}`);\n }\n }\n\n /**\n * Get the current artifact (for use by loader).\n */\n getArtifact(): BuilderArtifact | null {\n return this.currentArtifact;\n }\n}\n"],"mappings":"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"}
package/dist/loader.cjs CHANGED
@@ -1,5 +1,6 @@
1
1
  Object.defineProperty(exports, '__esModule', { value: true });
2
2
  let __soda_gql_builder_plugin_support = require("@soda-gql/builder/plugin-support");
3
+ let node_path = require("node:path");
3
4
  let __soda_gql_common = require("@soda-gql/common");
4
5
  let __soda_gql_babel = require("@soda-gql/babel");
5
6
 
@@ -37,20 +38,27 @@ const sodaGqlLoader = function(source, inputSourceMap) {
37
38
  callback(null, source, inputSourceMap);
38
39
  return;
39
40
  }
40
- const normalizedPath = (0, __soda_gql_common.normalizePath)(filename);
41
- if (!Object.values(artifact.elements).some((element) => (0, __soda_gql_common.normalizePath)(element.metadata.sourcePath) === normalizedPath)) {
41
+ const baseDir = session.config.baseDir;
42
+ const toRelativePath = (absolutePath) => {
43
+ return (0, __soda_gql_common.normalizePath)((0, node_path.relative)(baseDir, absolutePath));
44
+ };
45
+ const toAbsolutePath = (relativePath$1) => {
46
+ return (0, __soda_gql_common.normalizePath)((0, node_path.resolve)(baseDir, relativePath$1));
47
+ };
48
+ const relativePath = toRelativePath(filename);
49
+ if (!Object.values(artifact.elements).some((element) => (0, __soda_gql_common.normalizePath)(element.metadata.sourcePath) === relativePath)) {
42
50
  callback(null, source, inputSourceMap);
43
51
  return;
44
52
  }
45
53
  const sharedState = (0, __soda_gql_builder_plugin_support.getSharedState)(stateKey);
46
- const normalizedFilename = (0, __soda_gql_common.normalizePath)(filename);
54
+ const relativeFilename = toRelativePath(filename);
47
55
  if (sharedState.moduleAdjacency.size > 0) {
48
- const importers = sharedState.moduleAdjacency.get(normalizedFilename);
49
- if (importers) for (const importer of importers) this.addDependency(importer);
50
- for (const [importedFile, importingFiles] of sharedState.moduleAdjacency) if (importingFiles.has(normalizedFilename)) this.addDependency(importedFile);
56
+ const importers = sharedState.moduleAdjacency.get(relativeFilename);
57
+ if (importers) for (const importer of importers) this.addDependency(toAbsolutePath(importer));
58
+ for (const [importedFile, importingFiles] of sharedState.moduleAdjacency) if (importingFiles.has(relativeFilename)) this.addDependency(toAbsolutePath(importedFile));
51
59
  } else for (const element of Object.values(artifact.elements)) {
52
60
  const elementPath = element.metadata.sourcePath;
53
- if (elementPath && elementPath !== filename) this.addDependency(elementPath);
61
+ if (elementPath && elementPath !== relativePath) this.addDependency(toAbsolutePath(elementPath));
54
62
  }
55
63
  if (options.transformer === "swc") {
56
64
  const swcTransformer = (0, __soda_gql_builder_plugin_support.getSharedSwcTransformer)(stateKey);
@@ -1 +1 @@
1
- {"version":3,"file":"loader.cjs","names":["sodaGqlLoader: LoaderDefinitionFunction<WebpackLoaderOptions>","result"],"sources":["../src/loader.ts"],"sourcesContent":["import { createBabelTransformer } from \"@soda-gql/babel\";\nimport {\n createPluginSession,\n getSharedArtifact,\n getSharedPluginSession,\n getSharedState,\n getSharedSwcTransformer,\n getStateKey,\n type PluginSession,\n} from \"@soda-gql/builder/plugin-support\";\nimport { normalizePath } from \"@soda-gql/common\";\nimport type { LoaderDefinitionFunction } from \"webpack\";\nimport type { WebpackLoaderOptions } from \"./types\";\n\n/**\n * Ensure plugin session is initialized.\n * First tries to use shared session from plugin, falls back to creating own.\n */\nconst ensurePluginSession = (options: WebpackLoaderOptions): PluginSession | null => {\n const stateKey = getStateKey(options.configPath);\n\n // Try to use shared session from plugin first\n const sharedSession = getSharedPluginSession(stateKey);\n if (sharedSession) {\n return sharedSession;\n }\n\n // Fall back to creating own session (for standalone loader usage)\n return createPluginSession(\n {\n configPath: options.configPath,\n enabled: options.enabled,\n },\n \"@soda-gql/webpack-plugin/loader\",\n );\n};\n\n/**\n * Webpack loader that transforms soda-gql code using the babel-plugin.\n */\nconst sodaGqlLoader: LoaderDefinitionFunction<WebpackLoaderOptions> = function (source, inputSourceMap) {\n const callback = this.async();\n const options = this.getOptions();\n const filename = this.resourcePath;\n const stateKey = getStateKey(options.configPath);\n\n (async () => {\n try {\n const session = ensurePluginSession(options);\n if (!session) {\n // Plugin disabled or config load failed, pass through unchanged\n callback(null, source, inputSourceMap as Parameters<typeof callback>[2]);\n return;\n }\n\n // Try to use shared artifact from plugin first (more efficient in watch mode)\n let artifact = getSharedArtifact(stateKey);\n\n // Fall back to fetching artifact if not shared\n if (!artifact) {\n artifact = await session.getArtifactAsync();\n }\n\n if (!artifact) {\n callback(null, source, inputSourceMap as Parameters<typeof callback>[2]);\n return;\n }\n\n // Check if this file contains any soda-gql elements\n const normalizedPath = normalizePath(filename);\n const hasElements = Object.values(artifact.elements).some(\n (element) => normalizePath(element.metadata.sourcePath) === normalizedPath,\n );\n\n if (!hasElements) {\n // Not a soda-gql file, pass through unchanged\n callback(null, source, inputSourceMap as Parameters<typeof callback>[2]);\n return;\n }\n\n // Add dependencies based on module adjacency for precise HMR\n const sharedState = getSharedState(stateKey);\n const normalizedFilename = normalizePath(filename);\n\n // Use module adjacency for efficient dependency tracking\n // moduleAdjacency maps: importedFile -> Set<importingFiles>\n if (sharedState.moduleAdjacency.size > 0) {\n // Add files that import this file (reverse dependencies)\n const importers = sharedState.moduleAdjacency.get(normalizedFilename);\n if (importers) {\n for (const importer of importers) {\n this.addDependency(importer);\n }\n }\n\n // Add files that this file imports (forward dependencies)\n for (const [importedFile, importingFiles] of sharedState.moduleAdjacency) {\n if (importingFiles.has(normalizedFilename)) {\n this.addDependency(importedFile);\n }\n }\n } else {\n // Fallback: Add all soda-gql source files as dependencies (conservative approach)\n for (const element of Object.values(artifact.elements)) {\n const elementPath = element.metadata.sourcePath;\n if (elementPath && elementPath !== filename) {\n this.addDependency(elementPath);\n }\n }\n }\n\n // Use SWC transformer if configured and available\n if (options.transformer === \"swc\") {\n const swcTransformer = getSharedSwcTransformer(stateKey);\n if (swcTransformer) {\n const result = swcTransformer.transform({\n sourceCode: source,\n sourcePath: filename,\n inputSourceMap: inputSourceMap ? JSON.stringify(inputSourceMap) : undefined,\n });\n\n if (result.transformed) {\n const sourceMap = result.sourceMap ? JSON.parse(result.sourceMap) : undefined;\n callback(null, result.sourceCode, sourceMap);\n return;\n }\n // Not transformed (no soda-gql code in file), pass through\n callback(null, source, inputSourceMap as Parameters<typeof callback>[2]);\n return;\n }\n // SWC transformer not available, fall through to Babel\n console.warn(\n \"[@soda-gql/webpack-plugin] SWC transformer not available, falling back to Babel. \" +\n \"Ensure the plugin has transformer: 'swc' option set.\",\n );\n }\n\n // Transform using babel-transformer directly (default)\n const babelTransformer = createBabelTransformer({\n artifact,\n config: session.config,\n sourceMap: true,\n });\n\n const result = babelTransformer.transform({\n sourceCode: source,\n sourcePath: filename,\n inputSourceMap: inputSourceMap ? JSON.stringify(inputSourceMap) : undefined,\n });\n\n if (result.transformed) {\n const sourceMap = result.sourceMap ? JSON.parse(result.sourceMap) : undefined;\n callback(null, result.sourceCode, sourceMap);\n } else {\n callback(null, source, inputSourceMap as Parameters<typeof callback>[2]);\n }\n } catch (error) {\n callback(error as Error);\n }\n })();\n};\n\nexport default sodaGqlLoader;\n\n// Mark as non-raw (we handle string source code)\nexport const raw = false;\n"],"mappings":";;;;;;;;;;AAkBA,MAAM,uBAAuB,YAAwD;CAInF,MAAM,iIAHuB,QAAQ,WAAW,CAGM;AACtD,KAAI,cACF,QAAO;AAIT,mEACE;EACE,YAAY,QAAQ;EACpB,SAAS,QAAQ;EAClB,EACD,kCACD;;;;;AAMH,MAAMA,gBAAgE,SAAU,QAAQ,gBAAgB;CACtG,MAAM,WAAW,KAAK,OAAO;CAC7B,MAAM,UAAU,KAAK,YAAY;CACjC,MAAM,WAAW,KAAK;CACtB,MAAM,8DAAuB,QAAQ,WAAW;AAEhD,EAAC,YAAY;AACX,MAAI;GACF,MAAM,UAAU,oBAAoB,QAAQ;AAC5C,OAAI,CAAC,SAAS;AAEZ,aAAS,MAAM,QAAQ,eAAiD;AACxE;;GAIF,IAAI,oEAA6B,SAAS;AAG1C,OAAI,CAAC,SACH,YAAW,MAAM,QAAQ,kBAAkB;AAG7C,OAAI,CAAC,UAAU;AACb,aAAS,MAAM,QAAQ,eAAiD;AACxE;;GAIF,MAAM,sDAA+B,SAAS;AAK9C,OAAI,CAJgB,OAAO,OAAO,SAAS,SAAS,CAAC,MAClD,iDAA0B,QAAQ,SAAS,WAAW,KAAK,eAC7D,EAEiB;AAEhB,aAAS,MAAM,QAAQ,eAAiD;AACxE;;GAIF,MAAM,oEAA6B,SAAS;GAC5C,MAAM,0DAAmC,SAAS;AAIlD,OAAI,YAAY,gBAAgB,OAAO,GAAG;IAExC,MAAM,YAAY,YAAY,gBAAgB,IAAI,mBAAmB;AACrE,QAAI,UACF,MAAK,MAAM,YAAY,UACrB,MAAK,cAAc,SAAS;AAKhC,SAAK,MAAM,CAAC,cAAc,mBAAmB,YAAY,gBACvD,KAAI,eAAe,IAAI,mBAAmB,CACxC,MAAK,cAAc,aAAa;SAKpC,MAAK,MAAM,WAAW,OAAO,OAAO,SAAS,SAAS,EAAE;IACtD,MAAM,cAAc,QAAQ,SAAS;AACrC,QAAI,eAAe,gBAAgB,SACjC,MAAK,cAAc,YAAY;;AAMrC,OAAI,QAAQ,gBAAgB,OAAO;IACjC,MAAM,gFAAyC,SAAS;AACxD,QAAI,gBAAgB;KAClB,MAAMC,WAAS,eAAe,UAAU;MACtC,YAAY;MACZ,YAAY;MACZ,gBAAgB,iBAAiB,KAAK,UAAU,eAAe,GAAG;MACnE,CAAC;AAEF,SAAIA,SAAO,aAAa;MACtB,MAAM,YAAYA,SAAO,YAAY,KAAK,MAAMA,SAAO,UAAU,GAAG;AACpE,eAAS,MAAMA,SAAO,YAAY,UAAU;AAC5C;;AAGF,cAAS,MAAM,QAAQ,eAAiD;AACxE;;AAGF,YAAQ,KACN,wIAED;;GAUH,MAAM,sDAN0C;IAC9C;IACA,QAAQ,QAAQ;IAChB,WAAW;IACZ,CAAC,CAE8B,UAAU;IACxC,YAAY;IACZ,YAAY;IACZ,gBAAgB,iBAAiB,KAAK,UAAU,eAAe,GAAG;IACnE,CAAC;AAEF,OAAI,OAAO,aAAa;IACtB,MAAM,YAAY,OAAO,YAAY,KAAK,MAAM,OAAO,UAAU,GAAG;AACpE,aAAS,MAAM,OAAO,YAAY,UAAU;SAE5C,UAAS,MAAM,QAAQ,eAAiD;WAEnE,OAAO;AACd,YAAS,MAAe;;KAExB;;AAGN,qBAAe;AAGf,MAAa,MAAM"}
1
+ {"version":3,"file":"loader.cjs","names":["sodaGqlLoader: LoaderDefinitionFunction<WebpackLoaderOptions>","relativePath","result"],"sources":["../src/loader.ts"],"sourcesContent":["import { relative, resolve } from \"node:path\";\nimport { createBabelTransformer } from \"@soda-gql/babel\";\nimport {\n createPluginSession,\n getSharedArtifact,\n getSharedPluginSession,\n getSharedState,\n getSharedSwcTransformer,\n getStateKey,\n type PluginSession,\n} from \"@soda-gql/builder/plugin-support\";\nimport { normalizePath } from \"@soda-gql/common\";\nimport type { LoaderDefinitionFunction } from \"webpack\";\nimport type { WebpackLoaderOptions } from \"./types\";\n\n/**\n * Ensure plugin session is initialized.\n * First tries to use shared session from plugin, falls back to creating own.\n */\nconst ensurePluginSession = (options: WebpackLoaderOptions): PluginSession | null => {\n const stateKey = getStateKey(options.configPath);\n\n // Try to use shared session from plugin first\n const sharedSession = getSharedPluginSession(stateKey);\n if (sharedSession) {\n return sharedSession;\n }\n\n // Fall back to creating own session (for standalone loader usage)\n return createPluginSession(\n {\n configPath: options.configPath,\n enabled: options.enabled,\n },\n \"@soda-gql/webpack-plugin/loader\",\n );\n};\n\n/**\n * Webpack loader that transforms soda-gql code using the babel-plugin.\n */\nconst sodaGqlLoader: LoaderDefinitionFunction<WebpackLoaderOptions> = function (source, inputSourceMap) {\n const callback = this.async();\n const options = this.getOptions();\n const filename = this.resourcePath;\n const stateKey = getStateKey(options.configPath);\n\n (async () => {\n try {\n const session = ensurePluginSession(options);\n if (!session) {\n // Plugin disabled or config load failed, pass through unchanged\n callback(null, source, inputSourceMap as Parameters<typeof callback>[2]);\n return;\n }\n\n // Try to use shared artifact from plugin first (more efficient in watch mode)\n let artifact = getSharedArtifact(stateKey);\n\n // Fall back to fetching artifact if not shared\n if (!artifact) {\n artifact = await session.getArtifactAsync();\n }\n\n if (!artifact) {\n callback(null, source, inputSourceMap as Parameters<typeof callback>[2]);\n return;\n }\n\n const baseDir = session.config.baseDir;\n\n // Helper to convert absolute path to relative for matching against artifact sourcePaths\n const toRelativePath = (absolutePath: string): string => {\n return normalizePath(relative(baseDir, absolutePath));\n };\n\n // Helper to convert relative path to absolute for webpack's addDependency\n const toAbsolutePath = (relativePath: string): string => {\n return normalizePath(resolve(baseDir, relativePath));\n };\n\n // Check if this file contains any soda-gql elements\n // Convert absolute path to relative for matching against artifact sourcePaths\n const relativePath = toRelativePath(filename);\n const hasElements = Object.values(artifact.elements).some(\n (element) => normalizePath(element.metadata.sourcePath) === relativePath,\n );\n\n if (!hasElements) {\n // Not a soda-gql file, pass through unchanged\n callback(null, source, inputSourceMap as Parameters<typeof callback>[2]);\n return;\n }\n\n // Add dependencies based on module adjacency for precise HMR\n const sharedState = getSharedState(stateKey);\n const relativeFilename = toRelativePath(filename);\n\n // Use module adjacency for efficient dependency tracking\n // moduleAdjacency maps: importedFile -> Set<importingFiles> (now using relative paths)\n if (sharedState.moduleAdjacency.size > 0) {\n // Add files that import this file (reverse dependencies)\n const importers = sharedState.moduleAdjacency.get(relativeFilename);\n if (importers) {\n for (const importer of importers) {\n // Convert relative path to absolute for webpack\n this.addDependency(toAbsolutePath(importer));\n }\n }\n\n // Add files that this file imports (forward dependencies)\n for (const [importedFile, importingFiles] of sharedState.moduleAdjacency) {\n if (importingFiles.has(relativeFilename)) {\n // Convert relative path to absolute for webpack\n this.addDependency(toAbsolutePath(importedFile));\n }\n }\n } else {\n // Fallback: Add all soda-gql source files as dependencies (conservative approach)\n for (const element of Object.values(artifact.elements)) {\n const elementPath = element.metadata.sourcePath;\n if (elementPath && elementPath !== relativePath) {\n // Convert relative path to absolute for webpack\n this.addDependency(toAbsolutePath(elementPath));\n }\n }\n }\n\n // Use SWC transformer if configured and available\n if (options.transformer === \"swc\") {\n const swcTransformer = getSharedSwcTransformer(stateKey);\n if (swcTransformer) {\n const result = swcTransformer.transform({\n sourceCode: source,\n sourcePath: filename,\n inputSourceMap: inputSourceMap ? JSON.stringify(inputSourceMap) : undefined,\n });\n\n if (result.transformed) {\n const sourceMap = result.sourceMap ? JSON.parse(result.sourceMap) : undefined;\n callback(null, result.sourceCode, sourceMap);\n return;\n }\n // Not transformed (no soda-gql code in file), pass through\n callback(null, source, inputSourceMap as Parameters<typeof callback>[2]);\n return;\n }\n // SWC transformer not available, fall through to Babel\n console.warn(\n \"[@soda-gql/webpack-plugin] SWC transformer not available, falling back to Babel. \" +\n \"Ensure the plugin has transformer: 'swc' option set.\",\n );\n }\n\n // Transform using babel-transformer directly (default)\n const babelTransformer = createBabelTransformer({\n artifact,\n config: session.config,\n sourceMap: true,\n });\n\n const result = babelTransformer.transform({\n sourceCode: source,\n sourcePath: filename,\n inputSourceMap: inputSourceMap ? JSON.stringify(inputSourceMap) : undefined,\n });\n\n if (result.transformed) {\n const sourceMap = result.sourceMap ? JSON.parse(result.sourceMap) : undefined;\n callback(null, result.sourceCode, sourceMap);\n } else {\n callback(null, source, inputSourceMap as Parameters<typeof callback>[2]);\n }\n } catch (error) {\n callback(error as Error);\n }\n })();\n};\n\nexport default sodaGqlLoader;\n\n// Mark as non-raw (we handle string source code)\nexport const raw = false;\n"],"mappings":";;;;;;;;;;;AAmBA,MAAM,uBAAuB,YAAwD;CAInF,MAAM,iIAHuB,QAAQ,WAAW,CAGM;AACtD,KAAI,cACF,QAAO;AAIT,mEACE;EACE,YAAY,QAAQ;EACpB,SAAS,QAAQ;EAClB,EACD,kCACD;;;;;AAMH,MAAMA,gBAAgE,SAAU,QAAQ,gBAAgB;CACtG,MAAM,WAAW,KAAK,OAAO;CAC7B,MAAM,UAAU,KAAK,YAAY;CACjC,MAAM,WAAW,KAAK;CACtB,MAAM,8DAAuB,QAAQ,WAAW;AAEhD,EAAC,YAAY;AACX,MAAI;GACF,MAAM,UAAU,oBAAoB,QAAQ;AAC5C,OAAI,CAAC,SAAS;AAEZ,aAAS,MAAM,QAAQ,eAAiD;AACxE;;GAIF,IAAI,oEAA6B,SAAS;AAG1C,OAAI,CAAC,SACH,YAAW,MAAM,QAAQ,kBAAkB;AAG7C,OAAI,CAAC,UAAU;AACb,aAAS,MAAM,QAAQ,eAAiD;AACxE;;GAGF,MAAM,UAAU,QAAQ,OAAO;GAG/B,MAAM,kBAAkB,iBAAiC;AACvD,wEAA8B,SAAS,aAAa,CAAC;;GAIvD,MAAM,kBAAkB,mBAAiC;AACvD,uEAA6B,SAASC,eAAa,CAAC;;GAKtD,MAAM,eAAe,eAAe,SAAS;AAK7C,OAAI,CAJgB,OAAO,OAAO,SAAS,SAAS,CAAC,MAClD,iDAA0B,QAAQ,SAAS,WAAW,KAAK,aAC7D,EAEiB;AAEhB,aAAS,MAAM,QAAQ,eAAiD;AACxE;;GAIF,MAAM,oEAA6B,SAAS;GAC5C,MAAM,mBAAmB,eAAe,SAAS;AAIjD,OAAI,YAAY,gBAAgB,OAAO,GAAG;IAExC,MAAM,YAAY,YAAY,gBAAgB,IAAI,iBAAiB;AACnE,QAAI,UACF,MAAK,MAAM,YAAY,UAErB,MAAK,cAAc,eAAe,SAAS,CAAC;AAKhD,SAAK,MAAM,CAAC,cAAc,mBAAmB,YAAY,gBACvD,KAAI,eAAe,IAAI,iBAAiB,CAEtC,MAAK,cAAc,eAAe,aAAa,CAAC;SAKpD,MAAK,MAAM,WAAW,OAAO,OAAO,SAAS,SAAS,EAAE;IACtD,MAAM,cAAc,QAAQ,SAAS;AACrC,QAAI,eAAe,gBAAgB,aAEjC,MAAK,cAAc,eAAe,YAAY,CAAC;;AAMrD,OAAI,QAAQ,gBAAgB,OAAO;IACjC,MAAM,gFAAyC,SAAS;AACxD,QAAI,gBAAgB;KAClB,MAAMC,WAAS,eAAe,UAAU;MACtC,YAAY;MACZ,YAAY;MACZ,gBAAgB,iBAAiB,KAAK,UAAU,eAAe,GAAG;MACnE,CAAC;AAEF,SAAIA,SAAO,aAAa;MACtB,MAAM,YAAYA,SAAO,YAAY,KAAK,MAAMA,SAAO,UAAU,GAAG;AACpE,eAAS,MAAMA,SAAO,YAAY,UAAU;AAC5C;;AAGF,cAAS,MAAM,QAAQ,eAAiD;AACxE;;AAGF,YAAQ,KACN,wIAED;;GAUH,MAAM,sDAN0C;IAC9C;IACA,QAAQ,QAAQ;IAChB,WAAW;IACZ,CAAC,CAE8B,UAAU;IACxC,YAAY;IACZ,YAAY;IACZ,gBAAgB,iBAAiB,KAAK,UAAU,eAAe,GAAG;IACnE,CAAC;AAEF,OAAI,OAAO,aAAa;IACtB,MAAM,YAAY,OAAO,YAAY,KAAK,MAAM,OAAO,UAAU,GAAG;AACpE,aAAS,MAAM,OAAO,YAAY,UAAU;SAE5C,UAAS,MAAM,QAAQ,eAAiD;WAEnE,OAAO;AACd,YAAS,MAAe;;KAExB;;AAGN,qBAAe;AAGf,MAAa,MAAM"}
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.cts","names":[],"sources":["../src/loader.ts"],"sourcesContent":[],"mappings":";;;;;;;AAYoD;AAyJpD,cA7HM,aA6HU,EA7HK,wBA6HL,CA7H8B,oBA6H9B,CAAA;cAAH,GAAA"}
1
+ {"version":3,"file":"loader.d.cts","names":[],"sources":["../src/loader.ts"],"sourcesContent":[],"mappings":";;;;;;;AAaoD;AAyKpD,cA7IM,aA6IU,EA7IK,wBA6IL,CA7I8B,oBA6I9B,CAAA;cAAH,GAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.mts","names":[],"sources":["../src/loader.ts"],"sourcesContent":[],"mappings":";;;;;;;AAYoD;AAyJpD,cA7HM,aA6HU,EA7HK,wBA6HL,CA7H8B,oBA6H9B,CAAA;cAAH,GAAA"}
1
+ {"version":3,"file":"loader.d.mts","names":[],"sources":["../src/loader.ts"],"sourcesContent":[],"mappings":";;;;;;;AAaoD;AAyKpD,cA7IM,aA6IU,EA7IK,wBA6IL,CA7I8B,oBA6I9B,CAAA;cAAH,GAAA"}
package/dist/loader.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  import { createPluginSession, getSharedArtifact, getSharedPluginSession, getSharedState, getSharedSwcTransformer, getStateKey } from "@soda-gql/builder/plugin-support";
2
+ import { relative, resolve } from "node:path";
2
3
  import { normalizePath } from "@soda-gql/common";
3
4
  import { createBabelTransformer } from "@soda-gql/babel";
4
5
 
@@ -36,20 +37,27 @@ const sodaGqlLoader = function(source, inputSourceMap) {
36
37
  callback(null, source, inputSourceMap);
37
38
  return;
38
39
  }
39
- const normalizedPath = normalizePath(filename);
40
- if (!Object.values(artifact.elements).some((element) => normalizePath(element.metadata.sourcePath) === normalizedPath)) {
40
+ const baseDir = session.config.baseDir;
41
+ const toRelativePath = (absolutePath) => {
42
+ return normalizePath(relative(baseDir, absolutePath));
43
+ };
44
+ const toAbsolutePath = (relativePath$1) => {
45
+ return normalizePath(resolve(baseDir, relativePath$1));
46
+ };
47
+ const relativePath = toRelativePath(filename);
48
+ if (!Object.values(artifact.elements).some((element) => normalizePath(element.metadata.sourcePath) === relativePath)) {
41
49
  callback(null, source, inputSourceMap);
42
50
  return;
43
51
  }
44
52
  const sharedState = getSharedState(stateKey);
45
- const normalizedFilename = normalizePath(filename);
53
+ const relativeFilename = toRelativePath(filename);
46
54
  if (sharedState.moduleAdjacency.size > 0) {
47
- const importers = sharedState.moduleAdjacency.get(normalizedFilename);
48
- if (importers) for (const importer of importers) this.addDependency(importer);
49
- for (const [importedFile, importingFiles] of sharedState.moduleAdjacency) if (importingFiles.has(normalizedFilename)) this.addDependency(importedFile);
55
+ const importers = sharedState.moduleAdjacency.get(relativeFilename);
56
+ if (importers) for (const importer of importers) this.addDependency(toAbsolutePath(importer));
57
+ for (const [importedFile, importingFiles] of sharedState.moduleAdjacency) if (importingFiles.has(relativeFilename)) this.addDependency(toAbsolutePath(importedFile));
50
58
  } else for (const element of Object.values(artifact.elements)) {
51
59
  const elementPath = element.metadata.sourcePath;
52
- if (elementPath && elementPath !== filename) this.addDependency(elementPath);
60
+ if (elementPath && elementPath !== relativePath) this.addDependency(toAbsolutePath(elementPath));
53
61
  }
54
62
  if (options.transformer === "swc") {
55
63
  const swcTransformer = getSharedSwcTransformer(stateKey);
@@ -1 +1 @@
1
- {"version":3,"file":"loader.mjs","names":["sodaGqlLoader: LoaderDefinitionFunction<WebpackLoaderOptions>","result"],"sources":["../src/loader.ts"],"sourcesContent":["import { createBabelTransformer } from \"@soda-gql/babel\";\nimport {\n createPluginSession,\n getSharedArtifact,\n getSharedPluginSession,\n getSharedState,\n getSharedSwcTransformer,\n getStateKey,\n type PluginSession,\n} from \"@soda-gql/builder/plugin-support\";\nimport { normalizePath } from \"@soda-gql/common\";\nimport type { LoaderDefinitionFunction } from \"webpack\";\nimport type { WebpackLoaderOptions } from \"./types\";\n\n/**\n * Ensure plugin session is initialized.\n * First tries to use shared session from plugin, falls back to creating own.\n */\nconst ensurePluginSession = (options: WebpackLoaderOptions): PluginSession | null => {\n const stateKey = getStateKey(options.configPath);\n\n // Try to use shared session from plugin first\n const sharedSession = getSharedPluginSession(stateKey);\n if (sharedSession) {\n return sharedSession;\n }\n\n // Fall back to creating own session (for standalone loader usage)\n return createPluginSession(\n {\n configPath: options.configPath,\n enabled: options.enabled,\n },\n \"@soda-gql/webpack-plugin/loader\",\n );\n};\n\n/**\n * Webpack loader that transforms soda-gql code using the babel-plugin.\n */\nconst sodaGqlLoader: LoaderDefinitionFunction<WebpackLoaderOptions> = function (source, inputSourceMap) {\n const callback = this.async();\n const options = this.getOptions();\n const filename = this.resourcePath;\n const stateKey = getStateKey(options.configPath);\n\n (async () => {\n try {\n const session = ensurePluginSession(options);\n if (!session) {\n // Plugin disabled or config load failed, pass through unchanged\n callback(null, source, inputSourceMap as Parameters<typeof callback>[2]);\n return;\n }\n\n // Try to use shared artifact from plugin first (more efficient in watch mode)\n let artifact = getSharedArtifact(stateKey);\n\n // Fall back to fetching artifact if not shared\n if (!artifact) {\n artifact = await session.getArtifactAsync();\n }\n\n if (!artifact) {\n callback(null, source, inputSourceMap as Parameters<typeof callback>[2]);\n return;\n }\n\n // Check if this file contains any soda-gql elements\n const normalizedPath = normalizePath(filename);\n const hasElements = Object.values(artifact.elements).some(\n (element) => normalizePath(element.metadata.sourcePath) === normalizedPath,\n );\n\n if (!hasElements) {\n // Not a soda-gql file, pass through unchanged\n callback(null, source, inputSourceMap as Parameters<typeof callback>[2]);\n return;\n }\n\n // Add dependencies based on module adjacency for precise HMR\n const sharedState = getSharedState(stateKey);\n const normalizedFilename = normalizePath(filename);\n\n // Use module adjacency for efficient dependency tracking\n // moduleAdjacency maps: importedFile -> Set<importingFiles>\n if (sharedState.moduleAdjacency.size > 0) {\n // Add files that import this file (reverse dependencies)\n const importers = sharedState.moduleAdjacency.get(normalizedFilename);\n if (importers) {\n for (const importer of importers) {\n this.addDependency(importer);\n }\n }\n\n // Add files that this file imports (forward dependencies)\n for (const [importedFile, importingFiles] of sharedState.moduleAdjacency) {\n if (importingFiles.has(normalizedFilename)) {\n this.addDependency(importedFile);\n }\n }\n } else {\n // Fallback: Add all soda-gql source files as dependencies (conservative approach)\n for (const element of Object.values(artifact.elements)) {\n const elementPath = element.metadata.sourcePath;\n if (elementPath && elementPath !== filename) {\n this.addDependency(elementPath);\n }\n }\n }\n\n // Use SWC transformer if configured and available\n if (options.transformer === \"swc\") {\n const swcTransformer = getSharedSwcTransformer(stateKey);\n if (swcTransformer) {\n const result = swcTransformer.transform({\n sourceCode: source,\n sourcePath: filename,\n inputSourceMap: inputSourceMap ? JSON.stringify(inputSourceMap) : undefined,\n });\n\n if (result.transformed) {\n const sourceMap = result.sourceMap ? JSON.parse(result.sourceMap) : undefined;\n callback(null, result.sourceCode, sourceMap);\n return;\n }\n // Not transformed (no soda-gql code in file), pass through\n callback(null, source, inputSourceMap as Parameters<typeof callback>[2]);\n return;\n }\n // SWC transformer not available, fall through to Babel\n console.warn(\n \"[@soda-gql/webpack-plugin] SWC transformer not available, falling back to Babel. \" +\n \"Ensure the plugin has transformer: 'swc' option set.\",\n );\n }\n\n // Transform using babel-transformer directly (default)\n const babelTransformer = createBabelTransformer({\n artifact,\n config: session.config,\n sourceMap: true,\n });\n\n const result = babelTransformer.transform({\n sourceCode: source,\n sourcePath: filename,\n inputSourceMap: inputSourceMap ? JSON.stringify(inputSourceMap) : undefined,\n });\n\n if (result.transformed) {\n const sourceMap = result.sourceMap ? JSON.parse(result.sourceMap) : undefined;\n callback(null, result.sourceCode, sourceMap);\n } else {\n callback(null, source, inputSourceMap as Parameters<typeof callback>[2]);\n }\n } catch (error) {\n callback(error as Error);\n }\n })();\n};\n\nexport default sodaGqlLoader;\n\n// Mark as non-raw (we handle string source code)\nexport const raw = false;\n"],"mappings":";;;;;;;;;AAkBA,MAAM,uBAAuB,YAAwD;CAInF,MAAM,gBAAgB,uBAHL,YAAY,QAAQ,WAAW,CAGM;AACtD,KAAI,cACF,QAAO;AAIT,QAAO,oBACL;EACE,YAAY,QAAQ;EACpB,SAAS,QAAQ;EAClB,EACD,kCACD;;;;;AAMH,MAAMA,gBAAgE,SAAU,QAAQ,gBAAgB;CACtG,MAAM,WAAW,KAAK,OAAO;CAC7B,MAAM,UAAU,KAAK,YAAY;CACjC,MAAM,WAAW,KAAK;CACtB,MAAM,WAAW,YAAY,QAAQ,WAAW;AAEhD,EAAC,YAAY;AACX,MAAI;GACF,MAAM,UAAU,oBAAoB,QAAQ;AAC5C,OAAI,CAAC,SAAS;AAEZ,aAAS,MAAM,QAAQ,eAAiD;AACxE;;GAIF,IAAI,WAAW,kBAAkB,SAAS;AAG1C,OAAI,CAAC,SACH,YAAW,MAAM,QAAQ,kBAAkB;AAG7C,OAAI,CAAC,UAAU;AACb,aAAS,MAAM,QAAQ,eAAiD;AACxE;;GAIF,MAAM,iBAAiB,cAAc,SAAS;AAK9C,OAAI,CAJgB,OAAO,OAAO,SAAS,SAAS,CAAC,MAClD,YAAY,cAAc,QAAQ,SAAS,WAAW,KAAK,eAC7D,EAEiB;AAEhB,aAAS,MAAM,QAAQ,eAAiD;AACxE;;GAIF,MAAM,cAAc,eAAe,SAAS;GAC5C,MAAM,qBAAqB,cAAc,SAAS;AAIlD,OAAI,YAAY,gBAAgB,OAAO,GAAG;IAExC,MAAM,YAAY,YAAY,gBAAgB,IAAI,mBAAmB;AACrE,QAAI,UACF,MAAK,MAAM,YAAY,UACrB,MAAK,cAAc,SAAS;AAKhC,SAAK,MAAM,CAAC,cAAc,mBAAmB,YAAY,gBACvD,KAAI,eAAe,IAAI,mBAAmB,CACxC,MAAK,cAAc,aAAa;SAKpC,MAAK,MAAM,WAAW,OAAO,OAAO,SAAS,SAAS,EAAE;IACtD,MAAM,cAAc,QAAQ,SAAS;AACrC,QAAI,eAAe,gBAAgB,SACjC,MAAK,cAAc,YAAY;;AAMrC,OAAI,QAAQ,gBAAgB,OAAO;IACjC,MAAM,iBAAiB,wBAAwB,SAAS;AACxD,QAAI,gBAAgB;KAClB,MAAMC,WAAS,eAAe,UAAU;MACtC,YAAY;MACZ,YAAY;MACZ,gBAAgB,iBAAiB,KAAK,UAAU,eAAe,GAAG;MACnE,CAAC;AAEF,SAAIA,SAAO,aAAa;MACtB,MAAM,YAAYA,SAAO,YAAY,KAAK,MAAMA,SAAO,UAAU,GAAG;AACpE,eAAS,MAAMA,SAAO,YAAY,UAAU;AAC5C;;AAGF,cAAS,MAAM,QAAQ,eAAiD;AACxE;;AAGF,YAAQ,KACN,wIAED;;GAUH,MAAM,SANmB,uBAAuB;IAC9C;IACA,QAAQ,QAAQ;IAChB,WAAW;IACZ,CAAC,CAE8B,UAAU;IACxC,YAAY;IACZ,YAAY;IACZ,gBAAgB,iBAAiB,KAAK,UAAU,eAAe,GAAG;IACnE,CAAC;AAEF,OAAI,OAAO,aAAa;IACtB,MAAM,YAAY,OAAO,YAAY,KAAK,MAAM,OAAO,UAAU,GAAG;AACpE,aAAS,MAAM,OAAO,YAAY,UAAU;SAE5C,UAAS,MAAM,QAAQ,eAAiD;WAEnE,OAAO;AACd,YAAS,MAAe;;KAExB;;AAGN,qBAAe;AAGf,MAAa,MAAM"}
1
+ {"version":3,"file":"loader.mjs","names":["sodaGqlLoader: LoaderDefinitionFunction<WebpackLoaderOptions>","relativePath","result"],"sources":["../src/loader.ts"],"sourcesContent":["import { relative, resolve } from \"node:path\";\nimport { createBabelTransformer } from \"@soda-gql/babel\";\nimport {\n createPluginSession,\n getSharedArtifact,\n getSharedPluginSession,\n getSharedState,\n getSharedSwcTransformer,\n getStateKey,\n type PluginSession,\n} from \"@soda-gql/builder/plugin-support\";\nimport { normalizePath } from \"@soda-gql/common\";\nimport type { LoaderDefinitionFunction } from \"webpack\";\nimport type { WebpackLoaderOptions } from \"./types\";\n\n/**\n * Ensure plugin session is initialized.\n * First tries to use shared session from plugin, falls back to creating own.\n */\nconst ensurePluginSession = (options: WebpackLoaderOptions): PluginSession | null => {\n const stateKey = getStateKey(options.configPath);\n\n // Try to use shared session from plugin first\n const sharedSession = getSharedPluginSession(stateKey);\n if (sharedSession) {\n return sharedSession;\n }\n\n // Fall back to creating own session (for standalone loader usage)\n return createPluginSession(\n {\n configPath: options.configPath,\n enabled: options.enabled,\n },\n \"@soda-gql/webpack-plugin/loader\",\n );\n};\n\n/**\n * Webpack loader that transforms soda-gql code using the babel-plugin.\n */\nconst sodaGqlLoader: LoaderDefinitionFunction<WebpackLoaderOptions> = function (source, inputSourceMap) {\n const callback = this.async();\n const options = this.getOptions();\n const filename = this.resourcePath;\n const stateKey = getStateKey(options.configPath);\n\n (async () => {\n try {\n const session = ensurePluginSession(options);\n if (!session) {\n // Plugin disabled or config load failed, pass through unchanged\n callback(null, source, inputSourceMap as Parameters<typeof callback>[2]);\n return;\n }\n\n // Try to use shared artifact from plugin first (more efficient in watch mode)\n let artifact = getSharedArtifact(stateKey);\n\n // Fall back to fetching artifact if not shared\n if (!artifact) {\n artifact = await session.getArtifactAsync();\n }\n\n if (!artifact) {\n callback(null, source, inputSourceMap as Parameters<typeof callback>[2]);\n return;\n }\n\n const baseDir = session.config.baseDir;\n\n // Helper to convert absolute path to relative for matching against artifact sourcePaths\n const toRelativePath = (absolutePath: string): string => {\n return normalizePath(relative(baseDir, absolutePath));\n };\n\n // Helper to convert relative path to absolute for webpack's addDependency\n const toAbsolutePath = (relativePath: string): string => {\n return normalizePath(resolve(baseDir, relativePath));\n };\n\n // Check if this file contains any soda-gql elements\n // Convert absolute path to relative for matching against artifact sourcePaths\n const relativePath = toRelativePath(filename);\n const hasElements = Object.values(artifact.elements).some(\n (element) => normalizePath(element.metadata.sourcePath) === relativePath,\n );\n\n if (!hasElements) {\n // Not a soda-gql file, pass through unchanged\n callback(null, source, inputSourceMap as Parameters<typeof callback>[2]);\n return;\n }\n\n // Add dependencies based on module adjacency for precise HMR\n const sharedState = getSharedState(stateKey);\n const relativeFilename = toRelativePath(filename);\n\n // Use module adjacency for efficient dependency tracking\n // moduleAdjacency maps: importedFile -> Set<importingFiles> (now using relative paths)\n if (sharedState.moduleAdjacency.size > 0) {\n // Add files that import this file (reverse dependencies)\n const importers = sharedState.moduleAdjacency.get(relativeFilename);\n if (importers) {\n for (const importer of importers) {\n // Convert relative path to absolute for webpack\n this.addDependency(toAbsolutePath(importer));\n }\n }\n\n // Add files that this file imports (forward dependencies)\n for (const [importedFile, importingFiles] of sharedState.moduleAdjacency) {\n if (importingFiles.has(relativeFilename)) {\n // Convert relative path to absolute for webpack\n this.addDependency(toAbsolutePath(importedFile));\n }\n }\n } else {\n // Fallback: Add all soda-gql source files as dependencies (conservative approach)\n for (const element of Object.values(artifact.elements)) {\n const elementPath = element.metadata.sourcePath;\n if (elementPath && elementPath !== relativePath) {\n // Convert relative path to absolute for webpack\n this.addDependency(toAbsolutePath(elementPath));\n }\n }\n }\n\n // Use SWC transformer if configured and available\n if (options.transformer === \"swc\") {\n const swcTransformer = getSharedSwcTransformer(stateKey);\n if (swcTransformer) {\n const result = swcTransformer.transform({\n sourceCode: source,\n sourcePath: filename,\n inputSourceMap: inputSourceMap ? JSON.stringify(inputSourceMap) : undefined,\n });\n\n if (result.transformed) {\n const sourceMap = result.sourceMap ? JSON.parse(result.sourceMap) : undefined;\n callback(null, result.sourceCode, sourceMap);\n return;\n }\n // Not transformed (no soda-gql code in file), pass through\n callback(null, source, inputSourceMap as Parameters<typeof callback>[2]);\n return;\n }\n // SWC transformer not available, fall through to Babel\n console.warn(\n \"[@soda-gql/webpack-plugin] SWC transformer not available, falling back to Babel. \" +\n \"Ensure the plugin has transformer: 'swc' option set.\",\n );\n }\n\n // Transform using babel-transformer directly (default)\n const babelTransformer = createBabelTransformer({\n artifact,\n config: session.config,\n sourceMap: true,\n });\n\n const result = babelTransformer.transform({\n sourceCode: source,\n sourcePath: filename,\n inputSourceMap: inputSourceMap ? JSON.stringify(inputSourceMap) : undefined,\n });\n\n if (result.transformed) {\n const sourceMap = result.sourceMap ? JSON.parse(result.sourceMap) : undefined;\n callback(null, result.sourceCode, sourceMap);\n } else {\n callback(null, source, inputSourceMap as Parameters<typeof callback>[2]);\n }\n } catch (error) {\n callback(error as Error);\n }\n })();\n};\n\nexport default sodaGqlLoader;\n\n// Mark as non-raw (we handle string source code)\nexport const raw = false;\n"],"mappings":";;;;;;;;;;AAmBA,MAAM,uBAAuB,YAAwD;CAInF,MAAM,gBAAgB,uBAHL,YAAY,QAAQ,WAAW,CAGM;AACtD,KAAI,cACF,QAAO;AAIT,QAAO,oBACL;EACE,YAAY,QAAQ;EACpB,SAAS,QAAQ;EAClB,EACD,kCACD;;;;;AAMH,MAAMA,gBAAgE,SAAU,QAAQ,gBAAgB;CACtG,MAAM,WAAW,KAAK,OAAO;CAC7B,MAAM,UAAU,KAAK,YAAY;CACjC,MAAM,WAAW,KAAK;CACtB,MAAM,WAAW,YAAY,QAAQ,WAAW;AAEhD,EAAC,YAAY;AACX,MAAI;GACF,MAAM,UAAU,oBAAoB,QAAQ;AAC5C,OAAI,CAAC,SAAS;AAEZ,aAAS,MAAM,QAAQ,eAAiD;AACxE;;GAIF,IAAI,WAAW,kBAAkB,SAAS;AAG1C,OAAI,CAAC,SACH,YAAW,MAAM,QAAQ,kBAAkB;AAG7C,OAAI,CAAC,UAAU;AACb,aAAS,MAAM,QAAQ,eAAiD;AACxE;;GAGF,MAAM,UAAU,QAAQ,OAAO;GAG/B,MAAM,kBAAkB,iBAAiC;AACvD,WAAO,cAAc,SAAS,SAAS,aAAa,CAAC;;GAIvD,MAAM,kBAAkB,mBAAiC;AACvD,WAAO,cAAc,QAAQ,SAASC,eAAa,CAAC;;GAKtD,MAAM,eAAe,eAAe,SAAS;AAK7C,OAAI,CAJgB,OAAO,OAAO,SAAS,SAAS,CAAC,MAClD,YAAY,cAAc,QAAQ,SAAS,WAAW,KAAK,aAC7D,EAEiB;AAEhB,aAAS,MAAM,QAAQ,eAAiD;AACxE;;GAIF,MAAM,cAAc,eAAe,SAAS;GAC5C,MAAM,mBAAmB,eAAe,SAAS;AAIjD,OAAI,YAAY,gBAAgB,OAAO,GAAG;IAExC,MAAM,YAAY,YAAY,gBAAgB,IAAI,iBAAiB;AACnE,QAAI,UACF,MAAK,MAAM,YAAY,UAErB,MAAK,cAAc,eAAe,SAAS,CAAC;AAKhD,SAAK,MAAM,CAAC,cAAc,mBAAmB,YAAY,gBACvD,KAAI,eAAe,IAAI,iBAAiB,CAEtC,MAAK,cAAc,eAAe,aAAa,CAAC;SAKpD,MAAK,MAAM,WAAW,OAAO,OAAO,SAAS,SAAS,EAAE;IACtD,MAAM,cAAc,QAAQ,SAAS;AACrC,QAAI,eAAe,gBAAgB,aAEjC,MAAK,cAAc,eAAe,YAAY,CAAC;;AAMrD,OAAI,QAAQ,gBAAgB,OAAO;IACjC,MAAM,iBAAiB,wBAAwB,SAAS;AACxD,QAAI,gBAAgB;KAClB,MAAMC,WAAS,eAAe,UAAU;MACtC,YAAY;MACZ,YAAY;MACZ,gBAAgB,iBAAiB,KAAK,UAAU,eAAe,GAAG;MACnE,CAAC;AAEF,SAAIA,SAAO,aAAa;MACtB,MAAM,YAAYA,SAAO,YAAY,KAAK,MAAMA,SAAO,UAAU,GAAG;AACpE,eAAS,MAAMA,SAAO,YAAY,UAAU;AAC5C;;AAGF,cAAS,MAAM,QAAQ,eAAiD;AACxE;;AAGF,YAAQ,KACN,wIAED;;GAUH,MAAM,SANmB,uBAAuB;IAC9C;IACA,QAAQ,QAAQ;IAChB,WAAW;IACZ,CAAC,CAE8B,UAAU;IACxC,YAAY;IACZ,YAAY;IACZ,gBAAgB,iBAAiB,KAAK,UAAU,eAAe,GAAG;IACnE,CAAC;AAEF,OAAI,OAAO,aAAa;IACtB,MAAM,YAAY,OAAO,YAAY,KAAK,MAAM,OAAO,UAAU,GAAG;AACpE,aAAS,MAAM,OAAO,YAAY,UAAU;SAE5C,UAAS,MAAM,QAAQ,eAAiD;WAEnE,OAAO;AACd,YAAS,MAAe;;KAExB;;AAGN,qBAAe;AAGf,MAAa,MAAM"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soda-gql/webpack-plugin",
3
- "version": "0.11.9",
3
+ "version": "0.11.11",
4
4
  "description": "Webpack plugin for soda-gql with HMR support",
5
5
  "type": "module",
6
6
  "private": false,
@@ -59,18 +59,18 @@
59
59
  "./package.json": "./package.json"
60
60
  },
61
61
  "dependencies": {
62
- "@soda-gql/builder": "0.11.9",
63
- "@soda-gql/common": "0.11.9",
64
- "@soda-gql/config": "0.11.9",
65
- "@soda-gql/core": "0.11.9",
66
- "@soda-gql/babel": "0.11.9"
62
+ "@soda-gql/builder": "0.11.11",
63
+ "@soda-gql/common": "0.11.11",
64
+ "@soda-gql/config": "0.11.11",
65
+ "@soda-gql/core": "0.11.11",
66
+ "@soda-gql/babel": "0.11.11"
67
67
  },
68
68
  "devDependencies": {
69
- "@soda-gql/swc": "0.11.9"
69
+ "@soda-gql/swc": "0.11.11"
70
70
  },
71
71
  "peerDependencies": {
72
72
  "webpack": "^5.0.0",
73
- "@soda-gql/swc": "0.11.9"
73
+ "@soda-gql/swc": "0.11.11"
74
74
  },
75
75
  "optionalDependencies": {}
76
76
  }