@jay-framework/compiler-jay-stack 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -108,6 +108,93 @@ declare function transformActionImports(code: string, id: string, resolveActionM
108
108
  code: string;
109
109
  } | null>): Promise<TransformResult | null>;
110
110
 
111
+ /**
112
+ * Plugin Client Import Resolver
113
+ *
114
+ * Transforms imports from Jay plugin packages to use their /client subpath
115
+ * when in client build mode.
116
+ *
117
+ * This handles transitive plugin dependencies: when wix-stores imports from
118
+ * wix-server-client, the import should be rewritten to wix-server-client/client
119
+ * in client builds.
120
+ *
121
+ * Uses a `transform` hook instead of `resolveId` to ensure the rewrite happens
122
+ * before rollup's `external` option is evaluated.
123
+ *
124
+ * Detection:
125
+ * 1. Check if the imported package has a plugin.yaml (is a Jay plugin)
126
+ * 2. Check if the package exports a /client subpath
127
+ * 3. If both true, rewrite the import to use /client
128
+ */
129
+
130
+ /**
131
+ * Interface for detecting if a package is a Jay plugin with /client export.
132
+ * Extracted to allow mocking in tests.
133
+ */
134
+ interface PluginDetector {
135
+ /**
136
+ * Checks if a package is a Jay plugin with a /client export.
137
+ * @param packageName - The package name (e.g., '@jay-framework/wix-stores')
138
+ * @param projectRoot - The project root for resolution
139
+ * @returns true if the package should be rewritten to /client
140
+ */
141
+ isJayPluginWithClientExport(packageName: string, projectRoot: string): boolean;
142
+ }
143
+ /**
144
+ * Default implementation using Node's require.resolve.
145
+ */
146
+ declare function createDefaultPluginDetector(): PluginDetector;
147
+ /**
148
+ * Extracts the package name from an import source.
149
+ * Handles scoped packages like @jay-framework/wix-stores.
150
+ */
151
+ declare function extractPackageName(source: string): string | null;
152
+ /**
153
+ * Checks if the import is already using a subpath (not just the main entry).
154
+ */
155
+ declare function isSubpathImport(source: string, packageName: string): boolean;
156
+ interface TransformImportsOptions {
157
+ /** The source code to transform */
158
+ code: string;
159
+ /** Project root for plugin detection */
160
+ projectRoot: string;
161
+ /** File path for logging */
162
+ filePath: string;
163
+ /** Plugin detector (injectable for testing) */
164
+ pluginDetector: PluginDetector;
165
+ /** Enable verbose logging */
166
+ verbose?: boolean;
167
+ }
168
+ interface TransformImportsResult {
169
+ /** The transformed code */
170
+ code: string;
171
+ /** Whether any changes were made */
172
+ hasChanges: boolean;
173
+ }
174
+ /**
175
+ * Transforms import/export declarations in source code.
176
+ * Rewrites plugin package imports to use /client subpath.
177
+ *
178
+ * This is a pure function - all IO is handled by the pluginDetector.
179
+ */
180
+ declare function transformImports(options: TransformImportsOptions): TransformImportsResult;
181
+ interface PluginClientImportResolverOptions {
182
+ /** Project root directory for resolution */
183
+ projectRoot?: string;
184
+ /** Enable verbose logging */
185
+ verbose?: boolean;
186
+ /** Custom plugin detector (for testing) */
187
+ pluginDetector?: PluginDetector;
188
+ }
189
+ /**
190
+ * Creates a Vite plugin that transforms plugin package imports to /client
191
+ * in client builds.
192
+ *
193
+ * Uses the `transform` hook to rewrite import declarations before rollup's
194
+ * external option is evaluated.
195
+ */
196
+ declare function createPluginClientImportResolver(options?: PluginClientImportResolverOptions): Plugin;
197
+
111
198
  interface JayStackCompilerOptions extends JayRollupConfig {
112
199
  /**
113
200
  * Enable import chain tracking for debugging server code leaking into client builds.
@@ -156,4 +243,4 @@ interface JayStackCompilerOptions extends JayRollupConfig {
156
243
  */
157
244
  declare function jayStackCompiler(options?: JayStackCompilerOptions): Plugin[];
158
245
 
159
- export { type ActionMetadata, type BuildEnvironment, type ExtractedActions, type ImportChainTrackerOptions, type JayStackCompilerOptions, clearActionMetadataCache, createImportChainTracker, extractActionsFromSource, isActionImport, jayStackCompiler, transformActionImports, transformJayStackBuilder };
246
+ export { type ActionMetadata, type BuildEnvironment, type ExtractedActions, type ImportChainTrackerOptions, type JayStackCompilerOptions, type PluginClientImportResolverOptions, type PluginDetector, type TransformImportsOptions, type TransformImportsResult, clearActionMetadataCache, createDefaultPluginDetector, createImportChainTracker, createPluginClientImportResolver, extractActionsFromSource, extractPackageName, isActionImport, isSubpathImport, jayStackCompiler, transformActionImports, transformImports, transformJayStackBuilder };
package/dist/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { jayRuntime } from "@jay-framework/vite-plugin";
2
2
  import tsBridge from "@jay-framework/typescript-bridge";
3
3
  import { flattenVariable, isImportModuleVariableRoot, mkTransformer, SourceFileBindingResolver, areFlattenedAccessChainsEqual } from "@jay-framework/compiler";
4
- import * as fs from "node:fs";
5
4
  import * as path from "node:path";
5
+ import { createRequire } from "node:module";
6
+ import * as fs from "node:fs";
6
7
  const COMPONENT_SERVER_METHODS = /* @__PURE__ */ new Set([
7
8
  "withServices",
8
9
  "withLoadParams",
@@ -588,6 +589,130 @@ function createImportChainTracker(options = {}) {
588
589
  }
589
590
  };
590
591
  }
592
+ const require2 = createRequire(import.meta.url);
593
+ function createDefaultPluginDetector() {
594
+ const cache = /* @__PURE__ */ new Map();
595
+ return {
596
+ isJayPluginWithClientExport(packageName, projectRoot) {
597
+ const cacheKey = `${packageName}:${projectRoot}`;
598
+ if (cache.has(cacheKey)) {
599
+ return cache.get(cacheKey);
600
+ }
601
+ let result = false;
602
+ try {
603
+ require2.resolve(`${packageName}/plugin.yaml`, { paths: [projectRoot] });
604
+ try {
605
+ require2.resolve(`${packageName}/client`, { paths: [projectRoot] });
606
+ result = true;
607
+ } catch {
608
+ result = false;
609
+ }
610
+ } catch {
611
+ result = false;
612
+ }
613
+ cache.set(cacheKey, result);
614
+ return result;
615
+ }
616
+ };
617
+ }
618
+ function extractPackageName(source) {
619
+ if (source.startsWith(".") || source.startsWith("/")) {
620
+ return null;
621
+ }
622
+ if (source.startsWith("@")) {
623
+ const parts2 = source.split("/");
624
+ if (parts2.length >= 2) {
625
+ return `${parts2[0]}/${parts2[1]}`;
626
+ }
627
+ return null;
628
+ }
629
+ const parts = source.split("/");
630
+ return parts[0];
631
+ }
632
+ function isSubpathImport(source, packageName) {
633
+ return source.length > packageName.length && source[packageName.length] === "/";
634
+ }
635
+ const IMPORT_REGEX = /import\s+(.+?)\s+from\s+(['"])([^'"]+)\2/g;
636
+ const EXPORT_FROM_REGEX = /export\s+(.+?)\s+from\s+(['"])([^'"]+)\2/g;
637
+ function transformImports(options) {
638
+ const { code, projectRoot, filePath, pluginDetector, verbose = false } = options;
639
+ let hasChanges = false;
640
+ let result = code;
641
+ result = result.replace(IMPORT_REGEX, (match, clause, quote, source) => {
642
+ const packageName = extractPackageName(source);
643
+ if (!packageName)
644
+ return match;
645
+ if (isSubpathImport(source, packageName))
646
+ return match;
647
+ if (!pluginDetector.isJayPluginWithClientExport(packageName, projectRoot))
648
+ return match;
649
+ hasChanges = true;
650
+ const newSource = `${packageName}/client`;
651
+ if (verbose) {
652
+ console.log(
653
+ `[plugin-client-import] Rewriting import ${source} -> ${newSource} (in ${path.basename(filePath)})`
654
+ );
655
+ }
656
+ return `import ${clause} from ${quote}${newSource}${quote}`;
657
+ });
658
+ result = result.replace(EXPORT_FROM_REGEX, (match, clause, quote, source) => {
659
+ const packageName = extractPackageName(source);
660
+ if (!packageName)
661
+ return match;
662
+ if (isSubpathImport(source, packageName))
663
+ return match;
664
+ if (!pluginDetector.isJayPluginWithClientExport(packageName, projectRoot))
665
+ return match;
666
+ hasChanges = true;
667
+ const newSource = `${packageName}/client`;
668
+ if (verbose) {
669
+ console.log(
670
+ `[plugin-client-import] Rewriting export ${source} -> ${newSource} (in ${path.basename(filePath)})`
671
+ );
672
+ }
673
+ return `export ${clause} from ${quote}${newSource}${quote}`;
674
+ });
675
+ return { code: result, hasChanges };
676
+ }
677
+ function createPluginClientImportResolver(options = {}) {
678
+ const { verbose = false } = options;
679
+ let projectRoot = options.projectRoot || process.cwd();
680
+ let isSSRBuild = false;
681
+ const pluginDetector = options.pluginDetector || createDefaultPluginDetector();
682
+ return {
683
+ name: "jay-stack:plugin-client-import",
684
+ enforce: "pre",
685
+ configResolved(config) {
686
+ projectRoot = config.root || projectRoot;
687
+ isSSRBuild = !!config.build?.ssr;
688
+ },
689
+ transform(code, id, transformOptions) {
690
+ if (transformOptions?.ssr || isSSRBuild) {
691
+ return null;
692
+ }
693
+ if (!id.endsWith(".ts") && !id.endsWith(".js") && !id.includes(".ts?") && !id.includes(".js?")) {
694
+ return null;
695
+ }
696
+ if (id.includes("node_modules") && !id.includes("@jay-framework")) {
697
+ return null;
698
+ }
699
+ if (!code.includes("@jay-framework/") && !code.includes("from '@") && !code.includes('from "@')) {
700
+ return null;
701
+ }
702
+ const result = transformImports({
703
+ code,
704
+ projectRoot,
705
+ filePath: id,
706
+ pluginDetector,
707
+ verbose
708
+ });
709
+ if (!result.hasChanges) {
710
+ return null;
711
+ }
712
+ return { code: result.code };
713
+ }
714
+ };
715
+ }
591
716
  function jayStackCompiler(options = {}) {
592
717
  const { trackImports, ...jayOptions } = options;
593
718
  const moduleCache = /* @__PURE__ */ new Map();
@@ -597,6 +722,7 @@ function jayStackCompiler(options = {}) {
597
722
  if (shouldTrackImports) {
598
723
  plugins.push(createImportChainTracker(trackerOptions));
599
724
  }
725
+ plugins.push(createPluginClientImportResolver({ verbose: !!shouldTrackImports }));
600
726
  plugins.push(
601
727
  // First: Jay Stack code splitting transformation
602
728
  {
@@ -657,6 +783,13 @@ function jayStackCompiler(options = {}) {
657
783
  } else {
658
784
  return null;
659
785
  }
786
+ } else if (resolvedPath.endsWith(".js") && !fs.existsSync(resolvedPath)) {
787
+ const tsPath = resolvedPath.slice(0, -3) + ".ts";
788
+ if (fs.existsSync(tsPath)) {
789
+ resolvedPath = tsPath;
790
+ } else {
791
+ return null;
792
+ }
660
793
  }
661
794
  return `\0jay-action:${resolvedPath}`;
662
795
  },
@@ -703,10 +836,15 @@ function jayStackCompiler(options = {}) {
703
836
  }
704
837
  export {
705
838
  clearActionMetadataCache,
839
+ createDefaultPluginDetector,
706
840
  createImportChainTracker,
841
+ createPluginClientImportResolver,
707
842
  extractActionsFromSource,
843
+ extractPackageName,
708
844
  isActionImport,
845
+ isSubpathImport,
709
846
  jayStackCompiler,
710
847
  transformActionImports,
848
+ transformImports,
711
849
  transformJayStackBuilder
712
850
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jay-framework/compiler-jay-stack",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/index.js",
@@ -27,15 +27,15 @@
27
27
  "test:watch": "vitest"
28
28
  },
29
29
  "dependencies": {
30
- "@jay-framework/compiler": "^0.10.0",
31
- "@jay-framework/compiler-shared": "^0.10.0",
32
- "@jay-framework/typescript-bridge": "^0.5.0",
33
- "@jay-framework/vite-plugin": "^0.10.0",
30
+ "@jay-framework/compiler": "^0.11.0",
31
+ "@jay-framework/compiler-shared": "^0.11.0",
32
+ "@jay-framework/typescript-bridge": "^0.6.0",
33
+ "@jay-framework/vite-plugin": "^0.11.0",
34
34
  "typescript": "^5.3.3",
35
35
  "vite": "^5.0.11"
36
36
  },
37
37
  "devDependencies": {
38
- "@jay-framework/dev-environment": "^0.10.0",
38
+ "@jay-framework/dev-environment": "^0.11.0",
39
39
  "rimraf": "^5.0.5",
40
40
  "tsup": "^8.0.1",
41
41
  "vitest": "^1.2.1"