zelune 1.6.2 → 1.6.3

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.
@@ -237,8 +237,11 @@ export function viteCanvasApiMiddleware(workspaceRoot: string): Plugin {
237
237
 
238
238
  const activeRoot = getActiveProjectRoot(workspaceRoot);
239
239
  const layoutFilePath = path.resolve(activeRoot, '.canvas-layout.json');
240
- const urlObj = new URL(req.url, 'http://127.0.0.1');
241
- const pathname = urlObj.pathname;
240
+ const qIndex = req.url.indexOf('?');
241
+ const pathname = qIndex === -1 ? req.url : req.url.slice(0, qIndex);
242
+ const searchParams = new URLSearchParams(
243
+ qIndex === -1 ? '' : req.url.slice(qIndex + 1)
244
+ );
242
245
 
243
246
  try {
244
247
  // GET /api/screens
@@ -253,9 +256,9 @@ export function viteCanvasApiMiddleware(workspaceRoot: string): Plugin {
253
256
 
254
257
  // GET /api/inspect?file=...&astPath=...&line=...
255
258
  if (req.method === 'GET' && pathname === '/api/inspect') {
256
- const file = urlObj.searchParams.get('file') ?? '';
257
- const astPath = urlObj.searchParams.get('astPath') ?? '';
258
- const lineParam = urlObj.searchParams.get('line');
259
+ const file = searchParams.get('file') ?? '';
260
+ const astPath = searchParams.get('astPath') ?? '';
261
+ const lineParam = searchParams.get('line');
259
262
  const line = lineParam ? Number.parseInt(lineParam, 10) : undefined;
260
263
 
261
264
  const element = await inspectElement(workspaceRoot, { file, astPath, line });
@@ -2,14 +2,88 @@ import fs from 'node:fs/promises';
2
2
  import fsSync from 'node:fs';
3
3
  import path from 'node:path';
4
4
  import { parse } from '@babel/parser';
5
- import _traverse, { type NodePath } from '@babel/traverse';
6
5
  import _generate from '@babel/generator';
7
6
  import * as t from '@babel/types';
8
- import { getJsxTagName } from '../../plugins/viteRnSourceInject';
9
7
 
10
- const traverse = (_traverse as unknown as { default?: typeof _traverse }).default ?? _traverse;
11
8
  const generate = (_generate as unknown as { default?: typeof _generate }).default ?? _generate;
12
9
 
10
+ export interface AstNodePath<T extends t.Node = t.Node> {
11
+ node: T;
12
+ parentPath: AstNodePath<t.Node> | null;
13
+ isJSXElement(): this is AstNodePath<t.JSXElement>;
14
+ isJSXFragment(): this is AstNodePath<t.JSXFragment>;
15
+ findParent(predicate: (p: AstNodePath<t.Node>) => boolean): AstNodePath<t.Node> | null;
16
+ }
17
+
18
+ type NodePath<T extends t.Node = t.Node> = AstNodePath<T>;
19
+
20
+ export type AstVisitorMap = {
21
+ [K in t.Node['type']]?: (path: AstNodePath<Extract<t.Node, { type: K }>>) => void;
22
+ };
23
+
24
+ export function getJsxTagName(nameNode: t.JSXOpeningElement['name']): string {
25
+ if (t.isJSXIdentifier(nameNode)) {
26
+ return nameNode.name;
27
+ }
28
+ if (t.isJSXMemberExpression(nameNode)) {
29
+ return `${getJsxTagName(nameNode.object)}.${nameNode.property.name}`;
30
+ }
31
+ if (t.isJSXNamespacedName(nameNode)) {
32
+ return `${nameNode.namespace.name}:${nameNode.name.name}`;
33
+ }
34
+ return 'Unknown';
35
+ }
36
+
37
+ export function traverse(rootNode: t.Node, visitors: AstVisitorMap): void {
38
+ function createPath(node: t.Node, parentPath: AstNodePath<t.Node> | null): AstNodePath<t.Node> {
39
+ return {
40
+ node,
41
+ parentPath,
42
+ isJSXElement(): this is AstNodePath<t.JSXElement> {
43
+ return t.isJSXElement(node);
44
+ },
45
+ isJSXFragment(): this is AstNodePath<t.JSXFragment> {
46
+ return t.isJSXFragment(node);
47
+ },
48
+ findParent(predicate) {
49
+ let curr = parentPath;
50
+ while (curr) {
51
+ if (predicate(curr)) return curr;
52
+ curr = curr.parentPath;
53
+ }
54
+ return null;
55
+ },
56
+ };
57
+ }
58
+
59
+ function visit(node: unknown, parentPath: AstNodePath<t.Node> | null): void {
60
+ if (!node || typeof node !== 'object' || typeof (node as t.Node).type !== 'string') return;
61
+ const typedNode = node as t.Node;
62
+ const pathObj = createPath(typedNode, parentPath);
63
+ const handler = visitors[typedNode.type as t.Node['type']] as
64
+ | ((p: AstNodePath<t.Node>) => void)
65
+ | undefined;
66
+ if (typeof handler === 'function') {
67
+ handler(pathObj);
68
+ }
69
+ const keys = t.VISITOR_KEYS[typedNode.type];
70
+ if (!keys) return;
71
+ const rec = typedNode as unknown as Record<string, unknown>;
72
+ for (const key of keys) {
73
+ const child = rec[key];
74
+ if (Array.isArray(child)) {
75
+ for (let i = 0; i < child.length; i++) {
76
+ if (child[i]) visit(child[i], pathObj);
77
+ }
78
+ } else if (child && typeof child === 'object') {
79
+ visit(child, pathObj);
80
+ }
81
+ }
82
+ }
83
+
84
+ visit(rootNode, null);
85
+ }
86
+
13
87
  export interface NavigationEdge {
14
88
  id: string;
15
89
  fromScreen: string;
@@ -807,10 +881,7 @@ function resolveCandidateToScreenId(
807
881
  const trimmed = rawCandidate.trim();
808
882
  if (!trimmed || trimmed.length > 80) return null;
809
883
  if (
810
- trimmed.startsWith('http://') ||
811
- trimmed.startsWith('https://') ||
812
- trimmed.startsWith('mailto:') ||
813
- trimmed.startsWith('tel:') ||
884
+ /^[a-z][a-z0-9+.-]*:/i.test(trimmed) ||
814
885
  trimmed.startsWith('#') ||
815
886
  /\.(png|jpg|jpeg|svg|webp|gif|json|css)$/i.test(trimmed)
816
887
  ) {
package/vite.config.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { parse } from '@babel/parser';
2
2
  import { build, defineConfig, loadEnv } from 'vite';
3
- import react from '@vitejs/plugin-react';
4
3
  import fs from 'node:fs';
5
4
  import path from 'node:path';
6
5
  import { fileURLToPath } from 'node:url';
@@ -22,6 +21,7 @@ const workspaceRoot = process.env.ANTIGRAVITY_WORKSPACE_ROOT
22
21
 
23
22
  const targetProjectRoot = findMobileAppRoot(rawTargetRoot);
24
23
  const mockNavShimPath = path.resolve(__dirname, 'src/runtime/MockNavigationContext.tsx');
24
+ const reactNativeShimPath = path.resolve(__dirname, 'src/runtime/reactNativeShim.ts');
25
25
 
26
26
  function safeRealpath(targetPath: string): string {
27
27
  try {
@@ -42,7 +42,6 @@ function resolvePackageRootDir(pkgName: string): string {
42
42
 
43
43
  const resolvedReactDir = resolvePackageRootDir('react');
44
44
  const resolvedReactDomDir = resolvePackageRootDir('react-dom');
45
- const resolvedRnWebDir = resolvePackageRootDir('react-native-web');
46
45
  const resolvedLucideDir = resolvePackageRootDir('lucide-react');
47
46
 
48
47
  function loadPublicProjectEnv(roots: string[]): Record<string, string> {
@@ -288,7 +287,6 @@ export default defineConfig({
288
287
  viteReactNativeFallbackPlugin(targetProjectRoot, mockNavShimPath, workspaceRoot),
289
288
  viteVirtualScreensPlugin(targetProjectRoot),
290
289
  viteRnSourceInject(targetProjectRoot),
291
- react(),
292
290
  viteCanvasApiMiddleware(targetProjectRoot),
293
291
  ],
294
292
  optimizeDeps: {
@@ -299,22 +297,23 @@ export default defineConfig({
299
297
  'react/jsx-dev-runtime',
300
298
  'react-dom',
301
299
  'react-dom/client',
302
- 'react-native-web',
303
300
  'lucide-react',
304
301
  ],
305
302
  },
306
303
  esbuild: {
307
304
  // Ensure .tsx/.ts/.jsx/.js files (including RN .js files with JSX) are transpiled cleanly
305
+ jsx: 'automatic',
308
306
  include: /\.(tsx|ts|jsx|js)$/,
309
307
  exclude: [],
310
308
  loader: 'tsx',
311
309
  },
312
310
  resolve: {
313
- dedupe: ['react', 'react-dom', 'react-native-web'],
311
+ dedupe: ['react', 'react-dom'],
314
312
  alias: {
315
313
  react: resolvedReactDir,
316
314
  'react-dom': resolvedReactDomDir,
317
- 'react-native-web': resolvedRnWebDir,
315
+ 'react-native': reactNativeShimPath,
316
+ 'react-native-web': reactNativeShimPath,
318
317
  'lucide-react': resolvedLucideDir,
319
318
  },
320
319
  extensions: ['.web.tsx', '.web.ts', '.web.js', '.tsx', '.ts', '.jsx', '.js'],