@weaverse/react 5.5.0 → 5.5.1
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.mts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +80 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +80 -20
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -33,12 +33,15 @@ declare function replaceContentDataConnectors(content: string, dataContext: Data
|
|
|
33
33
|
* IMMUTABLE: Creates deep copies during processing to avoid mutating original data
|
|
34
34
|
* Handles strings, objects, arrays, and nested combinations
|
|
35
35
|
*
|
|
36
|
+
* PERFORMANCE: Now includes early exit if no placeholders detected
|
|
37
|
+
*
|
|
36
38
|
* @param data - The data to process (string, object, array, or primitive)
|
|
37
39
|
* @param dataContext - The data context for replacements
|
|
38
40
|
* @param visited - Set to track visited objects for circular reference protection
|
|
41
|
+
* @param forceClone - Internal flag to force cloning even if no placeholders (for parent immutability)
|
|
39
42
|
* @returns IMMUTABLE copy of the data with all string placeholders replaced
|
|
40
43
|
*/
|
|
41
|
-
declare function replaceContentDataConnectorsDeep<T>(data: T, dataContext: DataContext | null | undefined, visited?: WeakSet<WeakKey
|
|
44
|
+
declare function replaceContentDataConnectorsDeep<T>(data: T, dataContext: DataContext | null | undefined, visited?: WeakSet<WeakKey>, forceClone?: boolean): T;
|
|
42
45
|
|
|
43
46
|
declare function useWeaverse<T = Weaverse>(): T;
|
|
44
47
|
declare let useItemInstance: (id?: string) => WeaverseItemStore | null;
|
package/dist/index.d.ts
CHANGED
|
@@ -33,12 +33,15 @@ declare function replaceContentDataConnectors(content: string, dataContext: Data
|
|
|
33
33
|
* IMMUTABLE: Creates deep copies during processing to avoid mutating original data
|
|
34
34
|
* Handles strings, objects, arrays, and nested combinations
|
|
35
35
|
*
|
|
36
|
+
* PERFORMANCE: Now includes early exit if no placeholders detected
|
|
37
|
+
*
|
|
36
38
|
* @param data - The data to process (string, object, array, or primitive)
|
|
37
39
|
* @param dataContext - The data context for replacements
|
|
38
40
|
* @param visited - Set to track visited objects for circular reference protection
|
|
41
|
+
* @param forceClone - Internal flag to force cloning even if no placeholders (for parent immutability)
|
|
39
42
|
* @returns IMMUTABLE copy of the data with all string placeholders replaced
|
|
40
43
|
*/
|
|
41
|
-
declare function replaceContentDataConnectorsDeep<T>(data: T, dataContext: DataContext | null | undefined, visited?: WeakSet<WeakKey
|
|
44
|
+
declare function replaceContentDataConnectorsDeep<T>(data: T, dataContext: DataContext | null | undefined, visited?: WeakSet<WeakKey>, forceClone?: boolean): T;
|
|
42
45
|
|
|
43
46
|
declare function useWeaverse<T = Weaverse>(): T;
|
|
44
47
|
declare let useItemInstance: (id?: string) => WeaverseItemStore | null;
|
package/dist/index.js
CHANGED
|
@@ -58,6 +58,7 @@ var import_react2 = require("react");
|
|
|
58
58
|
// src/utils/data-connector.ts
|
|
59
59
|
var TEMPLATE_REGEX = /\{\{([^}]+)\}\}/g;
|
|
60
60
|
var ARRAY_INDEX_REGEX = /^(\w+)\[(\d+)\]$/;
|
|
61
|
+
var CACHE_EVICTION_RATIO = 0.25;
|
|
61
62
|
function isSafePropertyName(key) {
|
|
62
63
|
const dangerousPatterns = ["__proto__", "constructor", "prototype"];
|
|
63
64
|
return !dangerousPatterns.includes(key);
|
|
@@ -67,8 +68,8 @@ function parseRouteAndProperty(path, dataContext) {
|
|
|
67
68
|
return { routeKey: null, propertyPath: path };
|
|
68
69
|
}
|
|
69
70
|
const trimmedPath = path.trim();
|
|
70
|
-
const
|
|
71
|
-
const cacheKey = `${trimmedPath}::${
|
|
71
|
+
const dataHash = getDataContextHash(dataContext);
|
|
72
|
+
const cacheKey = `${trimmedPath}::${dataHash}`;
|
|
72
73
|
const cachedResult = routeParsingCache.get(cacheKey);
|
|
73
74
|
if (cachedResult) {
|
|
74
75
|
cachedResult.timestamp = Date.now();
|
|
@@ -91,7 +92,7 @@ function parseRouteAndProperty(path, dataContext) {
|
|
|
91
92
|
found = true;
|
|
92
93
|
break;
|
|
93
94
|
}
|
|
94
|
-
if (trimmedPath.startsWith(routeKey
|
|
95
|
+
if (trimmedPath.startsWith(`${routeKey}.`)) {
|
|
95
96
|
const propertyPath = trimmedPath.substring(routeKey.length + 1);
|
|
96
97
|
result = { routeKey, propertyPath };
|
|
97
98
|
found = true;
|
|
@@ -104,7 +105,7 @@ function parseRouteAndProperty(path, dataContext) {
|
|
|
104
105
|
if (routeParsingCache.size >= ROUTE_PARSING_CACHE_MAX_SIZE) {
|
|
105
106
|
const entries = Array.from(routeParsingCache.entries());
|
|
106
107
|
entries.sort((a, b) => a[1].timestamp - b[1].timestamp);
|
|
107
|
-
const toRemove = Math.floor(entries.length *
|
|
108
|
+
const toRemove = Math.floor(entries.length * CACHE_EVICTION_RATIO);
|
|
108
109
|
for (let i = 0; i < toRemove; i++) {
|
|
109
110
|
routeParsingCache.delete(entries[i][0]);
|
|
110
111
|
}
|
|
@@ -122,6 +123,8 @@ var fallbackCache = /* @__PURE__ */ new Map();
|
|
|
122
123
|
var FALLBACK_CACHE_MAX_SIZE = 50;
|
|
123
124
|
var routeParsingCache = /* @__PURE__ */ new Map();
|
|
124
125
|
var ROUTE_PARSING_CACHE_MAX_SIZE = 100;
|
|
126
|
+
var dataContextHashCache = /* @__PURE__ */ new WeakMap();
|
|
127
|
+
var hashCounter = 0;
|
|
125
128
|
function getNestedValue(obj, path, visited = /* @__PURE__ */ new WeakSet()) {
|
|
126
129
|
return path.split(".").reduce((current, key) => {
|
|
127
130
|
if (!current || typeof current !== "object") {
|
|
@@ -158,14 +161,16 @@ function sanitizeValue(value) {
|
|
|
158
161
|
const stringValue = String(value);
|
|
159
162
|
return stringValue.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'").replace(/\//g, "/");
|
|
160
163
|
}
|
|
161
|
-
function
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
return `${content}:${dataStr.slice(0, 100)}`;
|
|
165
|
-
} catch {
|
|
166
|
-
const keys = Object.keys(data).sort().join(",");
|
|
167
|
-
return `${content}:keys:${keys}`;
|
|
164
|
+
function getDataContextHash(data) {
|
|
165
|
+
if (!dataContextHashCache.has(data)) {
|
|
166
|
+
dataContextHashCache.set(data, `ctx_${++hashCounter}`);
|
|
168
167
|
}
|
|
168
|
+
const hash = dataContextHashCache.get(data);
|
|
169
|
+
return hash || `ctx_${++hashCounter}`;
|
|
170
|
+
}
|
|
171
|
+
function createCacheKey(content, data) {
|
|
172
|
+
const dataHash = getDataContextHash(data);
|
|
173
|
+
return `${content}:${dataHash}`;
|
|
169
174
|
}
|
|
170
175
|
function resolveDataFromContext(path, dataContext) {
|
|
171
176
|
if (!dataContext) {
|
|
@@ -209,7 +214,7 @@ function resolveDataFromContext(path, dataContext) {
|
|
|
209
214
|
if (fallbackCache.size >= FALLBACK_CACHE_MAX_SIZE) {
|
|
210
215
|
const entries = Array.from(fallbackCache.entries());
|
|
211
216
|
entries.sort((a, b) => a[1].timestamp - b[1].timestamp);
|
|
212
|
-
const toRemove = Math.floor(entries.length *
|
|
217
|
+
const toRemove = Math.floor(entries.length * CACHE_EVICTION_RATIO);
|
|
213
218
|
for (let i = 0; i < toRemove; i++) {
|
|
214
219
|
fallbackCache.delete(entries[i][0]);
|
|
215
220
|
}
|
|
@@ -231,8 +236,9 @@ function replaceContentDataConnectors(content, dataContext) {
|
|
|
231
236
|
}
|
|
232
237
|
try {
|
|
233
238
|
const cacheKey = createCacheKey(content, dataContext);
|
|
234
|
-
|
|
235
|
-
|
|
239
|
+
const cachedContent = templateCache.get(cacheKey);
|
|
240
|
+
if (cachedContent) {
|
|
241
|
+
return cachedContent;
|
|
236
242
|
}
|
|
237
243
|
const newContent = content.replace(TEMPLATE_REGEX, (match, path) => {
|
|
238
244
|
try {
|
|
@@ -260,10 +266,47 @@ function replaceContentDataConnectors(content, dataContext) {
|
|
|
260
266
|
return content;
|
|
261
267
|
}
|
|
262
268
|
}
|
|
263
|
-
function
|
|
269
|
+
function hasPlaceholders(data, visited = /* @__PURE__ */ new WeakSet()) {
|
|
270
|
+
if (typeof data === "string") {
|
|
271
|
+
TEMPLATE_REGEX.lastIndex = 0;
|
|
272
|
+
return TEMPLATE_REGEX.test(data);
|
|
273
|
+
}
|
|
274
|
+
if (typeof data !== "object" || data === null) {
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
if (data instanceof Date) {
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
if (visited.has(data)) {
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
visited.add(data);
|
|
284
|
+
try {
|
|
285
|
+
if (Array.isArray(data)) {
|
|
286
|
+
return data.some((item) => hasPlaceholders(item, visited));
|
|
287
|
+
}
|
|
288
|
+
for (const key of Object.keys(data)) {
|
|
289
|
+
try {
|
|
290
|
+
const value = data[key];
|
|
291
|
+
if (hasPlaceholders(value, visited)) {
|
|
292
|
+
return true;
|
|
293
|
+
}
|
|
294
|
+
} catch {
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return false;
|
|
298
|
+
} finally {
|
|
299
|
+
visited.delete(data);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
function replaceContentDataConnectorsDeep(data, dataContext, visited = /* @__PURE__ */ new WeakSet(), forceClone = false) {
|
|
264
303
|
if (!dataContext) {
|
|
265
304
|
return data;
|
|
266
305
|
}
|
|
306
|
+
const dataHasPlaceholders = hasPlaceholders(data, /* @__PURE__ */ new WeakSet());
|
|
307
|
+
if (!(dataHasPlaceholders || forceClone)) {
|
|
308
|
+
return data;
|
|
309
|
+
}
|
|
267
310
|
if (typeof data === "string") {
|
|
268
311
|
return replaceContentDataConnectors(data, dataContext);
|
|
269
312
|
}
|
|
@@ -279,18 +322,35 @@ function replaceContentDataConnectorsDeep(data, dataContext, visited = /* @__PUR
|
|
|
279
322
|
visited.add(data);
|
|
280
323
|
try {
|
|
281
324
|
if (data instanceof Date) {
|
|
282
|
-
|
|
325
|
+
if (forceClone || dataHasPlaceholders) {
|
|
326
|
+
return new Date(data.getTime());
|
|
327
|
+
}
|
|
328
|
+
return data;
|
|
283
329
|
}
|
|
284
330
|
if (Array.isArray(data)) {
|
|
285
331
|
const result2 = data.map(
|
|
286
|
-
(item) => replaceContentDataConnectorsDeep(
|
|
332
|
+
(item) => replaceContentDataConnectorsDeep(
|
|
333
|
+
item,
|
|
334
|
+
dataContext,
|
|
335
|
+
visited,
|
|
336
|
+
dataHasPlaceholders
|
|
337
|
+
)
|
|
287
338
|
);
|
|
288
339
|
return result2;
|
|
289
340
|
}
|
|
290
341
|
const result = {};
|
|
291
|
-
for (const
|
|
292
|
-
|
|
293
|
-
|
|
342
|
+
for (const key of Object.keys(data)) {
|
|
343
|
+
try {
|
|
344
|
+
const value = data[key];
|
|
345
|
+
result[key] = replaceContentDataConnectorsDeep(
|
|
346
|
+
value,
|
|
347
|
+
dataContext,
|
|
348
|
+
visited,
|
|
349
|
+
dataHasPlaceholders
|
|
350
|
+
);
|
|
351
|
+
} catch (propertyError) {
|
|
352
|
+
console.warn(`Error accessing property "${key}":`, propertyError);
|
|
353
|
+
}
|
|
294
354
|
}
|
|
295
355
|
return result;
|
|
296
356
|
} catch (error) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/context.ts","../src/hooks.ts","../src/utils/data-connector.ts","../src/renderer.tsx","../src/utils/css.ts"],"sourcesContent":["export * from '@weaverse/core'\nexport * from './context'\nexport * from './hooks'\nexport * from './renderer'\nexport * from './types'\n","import type { Weaverse } from '@weaverse/core'\nimport { createContext } from 'react'\n\nexport let WeaverseContext = createContext<Weaverse>({} as Weaverse)\nexport let WeaverseContextProvider = WeaverseContext.Provider\nexport let WeaverseItemContext = createContext<{\n id: string\n parentId: string\n}>({ id: '', parentId: '' })\n","import { Weaverse, type WeaverseItemStore } from '@weaverse/core'\nimport { useContext } from 'react'\nimport { WeaverseContext, WeaverseItemContext } from '~/context'\n\n// Re-export the data connector utilities\nexport {\n replaceContentDataConnectors,\n replaceContentDataConnectorsDeep,\n} from './utils/data-connector'\n\nexport function useWeaverse<T = Weaverse>() {\n let weaverse = useContext(WeaverseContext)\n return weaverse as T\n}\n\nexport let useItemInstance = (id?: string) => {\n let { id: currentId } = useContext(WeaverseItemContext)\n let instance = Weaverse.itemInstances.get(id || currentId)\n if (!instance) {\n console.log(`Item instance ${id} not found`)\n return null\n }\n return instance as WeaverseItemStore\n}\n\nexport let useParentInstance = () => {\n let { parentId } = useContext(WeaverseItemContext)\n return useItemInstance(parentId || '')\n}\n\nexport let useChildInstances = (id?: string) => {\n let currentInstance = useItemInstance(id)\n if (!currentInstance) {\n return []\n }\n let { itemInstances } = Weaverse\n\n let {\n data: { children },\n } = currentInstance\n return children\n .map(({ id }: { id: string }) => itemInstances.get(id))\n .filter(Boolean) as WeaverseItemStore[]\n}\n","// Data connector utilities for replacing placeholders with real data\n// Generic data context type for flexible usage\nexport type DataContext = Record<string, unknown>\n\n// Cached regex pattern for better performance\nconst TEMPLATE_REGEX = /\\{\\{([^}]+)\\}\\}/g\nconst ARRAY_INDEX_REGEX = /^(\\w+)\\[(\\d+)\\]$/\n\n/**\n * Validates that a property name is safe to access (prevents prototype pollution)\n * Enhanced to handle route-specific patterns with special characters\n */\nfunction isSafePropertyName(key: string): boolean {\n // Block dangerous prototype pollution patterns\n const dangerousPatterns = ['__proto__', 'constructor', 'prototype']\n return !dangerousPatterns.includes(key)\n}\n\n/**\n * Parses a template path into route key and property path components\n * Handles complex routes like: routes/($locale).blogs.$blogHandle.$articleHandle\n * Enhanced with caching for improved performance\n *\n * @param path - The full path from template (e.g., \"routes/($locale)._index.weaverseData.page.name\")\n * @param dataContext - Available route data context\n * @returns Object with routeKey and propertyPath\n */\nfunction parseRouteAndProperty(\n path: string,\n dataContext: DataContext\n): {\n routeKey: string | null\n propertyPath: string\n} {\n if (!dataContext || typeof path !== 'string') {\n return { routeKey: null, propertyPath: path }\n }\n\n const trimmedPath = path.trim()\n\n // Create a cache key that includes available routes for context awareness\n const availableRouteKeys = Object.keys(dataContext).sort().join('|')\n const cacheKey = `${trimmedPath}::${availableRouteKeys}`\n\n // Check cache first\n const cachedResult = routeParsingCache.get(cacheKey)\n if (cachedResult) {\n // Update timestamp on cache hit\n cachedResult.timestamp = Date.now()\n return {\n routeKey: cachedResult.routeKey,\n propertyPath: cachedResult.propertyPath,\n }\n }\n\n // Get all available routes and sort by length (longest first for specificity)\n const availableRoutes = Object.keys(dataContext).sort(\n (a, b) => b.length - a.length\n )\n\n let result: { routeKey: string | null; propertyPath: string } = {\n routeKey: null,\n propertyPath: trimmedPath,\n }\n\n // Try to find the longest matching route key\n let found = false\n for (const routeKey of availableRoutes) {\n // Exact match\n if (trimmedPath === routeKey) {\n result = { routeKey, propertyPath: '' }\n found = true\n break\n }\n\n // Route key with property path\n if (trimmedPath.startsWith(routeKey + '.')) {\n const propertyPath = trimmedPath.substring(routeKey.length + 1)\n result = { routeKey, propertyPath }\n found = true\n break\n }\n }\n\n if (!found) {\n // No route key found, treat entire path as property path\n result = { routeKey: null, propertyPath: trimmedPath }\n }\n\n // Cache the result\n if (routeParsingCache.size >= ROUTE_PARSING_CACHE_MAX_SIZE) {\n // Clean cache by removing oldest entries\n const entries = Array.from(routeParsingCache.entries())\n entries.sort((a, b) => a[1].timestamp - b[1].timestamp)\n const toRemove = Math.floor(entries.length * 0.25)\n for (let i = 0; i < toRemove; i++) {\n routeParsingCache.delete(entries[i][0])\n }\n }\n\n routeParsingCache.set(cacheKey, {\n routeKey: result.routeKey,\n propertyPath: result.propertyPath,\n timestamp: Date.now(),\n })\n\n return result\n}\n\n// Simple cache for parsed templates (max 100 entries)\nconst templateCache = new Map<string, string>()\nconst MAX_CACHE_SIZE = 100\n\n// Cache for fallback lookups to improve performance (moved to module level to prevent memory leaks)\nconst fallbackCache = new Map<\n string,\n { routeKey: string; value: unknown; timestamp: number }\n>()\nconst FALLBACK_CACHE_MAX_SIZE = 50\n\n// Route parsing cache for performance optimization\nconst routeParsingCache = new Map<\n string,\n { routeKey: string | null; propertyPath: string; timestamp: number }\n>()\nconst ROUTE_PARSING_CACHE_MAX_SIZE = 100\n\n/**\n * Safely gets a nested value from an object using dot notation path\n * Supports array indexing with [index] syntax\n * @param obj - The object to traverse\n * @param path - Dot notation path (e.g., \"user.name\" or \"items[0].title\")\n * @param visited - Set to track visited objects for circular reference protection\n * @returns The resolved value or undefined if not found\n */\nfunction getNestedValue(\n obj: unknown,\n path: string,\n visited = new WeakSet()\n): unknown {\n return path.split('.').reduce((current, key) => {\n if (!current || typeof current !== 'object') {\n return\n }\n\n // Protect against circular references\n if (visited.has(current as WeakKey)) {\n console.warn('Circular reference detected in data connector path:', path)\n return\n }\n\n // Add to circular reference tracking\n visited.add(current as WeakKey)\n\n // Handle array indexing like items[0] or items[1]\n const arrayMatch = key.match(ARRAY_INDEX_REGEX)\n if (arrayMatch) {\n const [, arrayKey, index] = arrayMatch\n const arrayObj = (current as Record<string, unknown>)[arrayKey]\n if (Array.isArray(arrayObj)) {\n const indexNum = Number.parseInt(index, 10)\n if (indexNum >= 0 && indexNum < arrayObj.length) {\n return arrayObj[indexNum]\n }\n }\n return\n }\n\n // Handle regular object property access with security validation\n if (!isSafePropertyName(key)) {\n console.warn(`Unsafe property access attempted: ${key}`)\n return\n }\n\n return current !== null && key in current\n ? (current as Record<string, unknown>)[key]\n : undefined\n }, obj)\n}\n\n/**\n * Sanitizes a string value to prevent XSS attacks\n * @param value - The value to sanitize\n * @returns Sanitized string safe for HTML rendering\n */\nfunction sanitizeValue(value: unknown): string {\n if (value === null || value === undefined) {\n return ''\n }\n\n const stringValue = String(value)\n\n // Basic HTML entity encoding to prevent XSS\n return stringValue\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n .replace(/\\//g, '/')\n}\n\n/**\n * Creates a safe cache key from content and data\n * Handles circular references by using a simplified approach\n */\nfunction createCacheKey(\n content: string,\n data: Record<string, unknown>\n): string {\n try {\n // Try a simple JSON stringification with a limit\n const dataStr = JSON.stringify(data)\n return `${content}:${dataStr.slice(0, 100)}`\n } catch {\n // If JSON.stringify fails (circular references), use a simpler approach\n const keys = Object.keys(data).sort().join(',')\n return `${content}:keys:${keys}`\n }\n}\n\n/**\n * Resolves data from the flat route-keyed data context\n * Enhanced to support complex route patterns with special characters\n * Supports: {{root.layout.shop.name}}, {{routes/($locale)._index.data}}, {{routes/($locale).blogs.$handle.$article.content}}\n */\nfunction resolveDataFromContext(\n path: string,\n dataContext: DataContext | null | undefined\n): unknown {\n if (!dataContext) {\n return\n }\n\n const trimmedPath = path.trim()\n\n // Use intelligent route parsing to separate route key from property path\n const { routeKey, propertyPath } = parseRouteAndProperty(\n trimmedPath,\n dataContext\n )\n\n // If we found a specific route key, resolve from that route's data\n if (routeKey && dataContext[routeKey]) {\n const routeData = dataContext[routeKey]\n if (typeof routeData === 'object' && routeData !== null) {\n if (propertyPath) {\n return getNestedValue(routeData, propertyPath)\n }\n return routeData\n }\n }\n\n // Fallback: search across all route data for backward compatibility\n // This handles cases like {{shop.name}} without route prefix\n\n // Check cache first\n const cachedResult = fallbackCache.get(trimmedPath)\n if (cachedResult && dataContext[cachedResult.routeKey]) {\n const value = getNestedValue(\n dataContext[cachedResult.routeKey],\n trimmedPath\n )\n if (value !== undefined) {\n // Update timestamp on cache hit\n cachedResult.timestamp = Date.now()\n return value\n }\n }\n\n // Search with priority order (most common routes first)\n const priorityRoutes = ['root', 'routes/product', 'routes/collection']\n const allRoutes = [\n ...priorityRoutes,\n ...Object.keys(dataContext).filter((k) => !priorityRoutes.includes(k)),\n ]\n\n for (const routeKey of allRoutes) {\n const routeData = dataContext[routeKey]\n if (routeData && typeof routeData === 'object' && routeData !== null) {\n const value = getNestedValue(routeData, trimmedPath)\n if (value !== undefined) {\n // Clean cache if it's getting too large\n if (fallbackCache.size >= FALLBACK_CACHE_MAX_SIZE) {\n const entries = Array.from(fallbackCache.entries())\n entries.sort((a, b) => a[1].timestamp - b[1].timestamp)\n // Remove oldest 25% of entries\n const toRemove = Math.floor(entries.length * 0.25)\n for (let i = 0; i < toRemove; i++) {\n fallbackCache.delete(entries[i][0])\n }\n }\n fallbackCache.set(trimmedPath, {\n routeKey,\n value,\n timestamp: Date.now(),\n })\n return value\n }\n }\n }\n\n // Final fallback: try direct access (for non-route-keyed legacy data)\n return getNestedValue(dataContext, trimmedPath)\n}\n\n/**\n * Replaces data connector placeholders in content with actual values from data context\n * Supports {{path}} syntax with dot notation, array indexing, and route prefixes\n *\n * Enhanced syntax:\n * - {{root.siteSettings.title}} - Access root route data\n * - {{layout.navigation.items}} - Access layout route data\n * - {{parent.category.name}} - Access parent route data\n * - {{current.product.title}} - Access current route data\n * - {{user.name}} - Auto-resolved from combined data (backward compatible)\n *\n * @param content - The content string containing {{}} placeholders\n * @param dataContext - The enhanced WeaverseDataContext with route-keyed data\n * @returns The content with placeholders replaced by actual values\n */\nexport function replaceContentDataConnectors(\n content: string,\n dataContext: DataContext | null | undefined\n): string {\n if (!dataContext || typeof content !== 'string') {\n return content\n }\n\n try {\n // Simplified caching - dataContext is already the combined data\n const cacheKey = createCacheKey(content, dataContext)\n\n if (templateCache.has(cacheKey)) {\n return templateCache.get(cacheKey)!\n }\n\n const newContent = content.replace(TEMPLATE_REGEX, (match, path) => {\n try {\n const value = resolveDataFromContext(path, dataContext)\n\n if (value === undefined || value === null) {\n return match // Return original placeholder if value not found\n }\n\n return sanitizeValue(value)\n } catch (pathError) {\n console.warn(\n `Error resolving data connector path \"${path}\":`,\n pathError\n )\n return match\n }\n })\n\n // Cache the result (with size limit)\n if (templateCache.size >= MAX_CACHE_SIZE) {\n const firstKey = templateCache.keys().next().value\n templateCache.delete(firstKey)\n }\n templateCache.set(cacheKey, newContent)\n\n return newContent\n } catch (error) {\n console.warn('Error processing data connectors:', error, { content })\n return content\n }\n}\n\n/**\n * Recursively replaces data connector placeholders in any data structure\n * IMMUTABLE: Creates deep copies during processing to avoid mutating original data\n * Handles strings, objects, arrays, and nested combinations\n *\n * @param data - The data to process (string, object, array, or primitive)\n * @param dataContext - The data context for replacements\n * @param visited - Set to track visited objects for circular reference protection\n * @returns IMMUTABLE copy of the data with all string placeholders replaced\n */\nexport function replaceContentDataConnectorsDeep<T>(\n data: T,\n dataContext: DataContext | null | undefined,\n visited = new WeakSet()\n): T {\n if (!dataContext) {\n return data\n }\n\n // Handle primitive types - no cloning needed for primitives\n if (typeof data === 'string') {\n return replaceContentDataConnectors(data, dataContext) as T\n }\n\n if (typeof data !== 'object' || data === null) {\n return data\n }\n\n // Protect against circular references\n if (visited.has(data as WeakKey)) {\n console.warn(\n 'Circular reference detected in deep data connector replacement'\n )\n return data\n }\n\n // Add to circular reference tracking\n visited.add(data as WeakKey)\n\n try {\n // Handle special objects that should be cloned as-is\n if (data instanceof Date) {\n return new Date(data.getTime()) as T\n }\n\n // Handle arrays - create new array with processed items\n if (Array.isArray(data)) {\n const result = data.map((item) =>\n replaceContentDataConnectorsDeep(item, dataContext, visited)\n ) as T\n return result\n }\n\n // Handle plain objects - create new object with processed values\n const result = {} as T\n for (const [key, value] of Object.entries(data)) {\n ;(result as Record<string, unknown>)[key] =\n replaceContentDataConnectorsDeep(value, dataContext, visited)\n }\n\n return result\n } catch (error) {\n console.warn('Error in deep data connector replacement:', error)\n return data\n } finally {\n // Remove from tracking when done processing this object\n visited.delete(data as WeakKey)\n }\n}\n","import clsx from 'clsx'\nimport React, { memo, useEffect, useRef } from 'react'\nimport { useItemInstance, useWeaverse } from '~/hooks'\nimport { WeaverseContextProvider, WeaverseItemContext } from './context'\nimport type { ItemComponentProps, WeaverseRootPropsType } from './types'\nimport { generateItemClassName } from './utils/css'\nimport { replaceContentDataConnectorsDeep } from './utils/data-connector'\n\nconst REACT_VERSION_THRESHOLD = 18\nconst reactVersion = Number(React.version?.split('.')[0]) || 0\n\n// Create a safe version of useSyncExternalStore that works in both client and server environments\nexport const useSafeExternalStore = (\n subscribe: any,\n getSnapshot: any,\n getServerSnapshot: any = getSnapshot\n) => {\n // In server environment or during SSR, just return the snapshot directly\n if (typeof window === 'undefined') {\n return getServerSnapshot()\n }\n\n // In client environment, use React.useSyncExternalStore if available (React 18+)\n if (React.useSyncExternalStore) {\n // biome-ignore lint/correctness/useHookAtTopLevel: <$>\n return React.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot)\n }\n\n // Fallback for older React versions - just return the current snapshot\n return getSnapshot()\n}\n\nexport const WeaverseRoot = memo(({ context }: WeaverseRootPropsType) => {\n const data = useSafeExternalStore(\n context.subscribe,\n context.getSnapShot,\n context.getSnapShot\n )\n const rootRef = useRef<HTMLElement>(null)\n\n useEffect(() => {\n context.contentRootElement = rootRef.current\n }, [context])\n\n const eventHandlers = context?.studioBridge?.eventHandlers || {}\n const themeClass = context.stitchesInstance.theme.className\n\n if (context.projectId) {\n return (\n <div\n className={`weaverse-content-root ${themeClass}`}\n {...eventHandlers}\n data-weaverse-project-id={context.projectId}\n data-weaverse-template-id={data.id}\n ref={rootRef}\n >\n <WeaverseContextProvider value={context}>\n <ItemInstance\n id={context.data.rootId || context.projectId}\n parentId={''}\n />\n </WeaverseContextProvider>\n </div>\n )\n }\n return null\n})\nWeaverseRoot.displayName = 'WeaverseRoot'\nconst ItemComponent = memo(({ instance }: ItemComponentProps) => {\n const context = useWeaverse()\n const { stitchesInstance, elementRegistry, platformType } = context\n const data = useSafeExternalStore(\n instance.subscribe,\n instance.getSnapShot,\n instance.getSnapShot\n )\n const {\n id,\n type,\n childIds = [],\n children = [],\n\n createdAt,\n updatedAt,\n deletedAt,\n css,\n __hidden,\n // Need to get rid of this `data` property\n data: _,\n ...rest\n } = data\n\n // Replace data connectors in all component data (handles strings, objects, and arrays recursively)\n // IMMUTABLE: Process the entire rest object to avoid mutating original content\n const processedRest = replaceContentDataConnectorsDeep(\n rest,\n context.dataContext\n )\n\n useEffect(() => {\n if (!instance.ref.current) {\n // Fallback `ref` if the element isn't created by `React.forwardRef`\n Object.assign(instance.ref, {\n current: document.querySelector(`[data-wv-id=\"${id}\"]`),\n })\n }\n }, [instance, id])\n\n if (__hidden) {\n return null\n }\n\n const Element = elementRegistry.get(type)\n\n if (Element?.Component) {\n const Component = Element.Component\n Component.displayName = type\n if (\n Component.$$typeof === Symbol.for('react.forward_ref') ||\n reactVersion > REACT_VERSION_THRESHOLD\n ) {\n processedRest.ref = instance.ref\n }\n const childItems = children?.length\n ? children\n : childIds?.length\n ? childIds.map((cid: string) => ({ id: cid }))\n : []\n\n const renderChildren = childItems.map(\n (item: { id: string }, index: number) => (\n <ItemInstance id={item.id} key={`${item.id}-${index}`} parentId={id} />\n )\n )\n\n return (\n <Component\n {...processedRest}\n children={renderChildren.length ? renderChildren : undefined}\n className={clsx(\n platformType !== 'shopify-hydrogen' &&\n generateItemClassName(instance, stitchesInstance),\n processedRest.data?.className\n )}\n data-wv-id={id}\n data-wv-type={type}\n key={id}\n />\n )\n }\n instance._store.deleted = true\n return null\n})\nItemComponent.displayName = 'WeaverseComponent'\n\nconst ItemInstance = memo(\n ({ id, parentId }: { id: string; parentId: string }) => {\n const instance = useItemInstance(id)\n if (!instance) {\n return <div style={{ display: 'none' }}>Item instance {id} not found</div>\n }\n return (\n <WeaverseItemContext.Provider value={{ parentId, id }}>\n <ItemComponent instance={instance} key={id} />\n </WeaverseItemContext.Provider>\n )\n }\n)\nItemInstance.displayName = 'WeaverseInstanceProvider'\n","import type Stitches from '@stitches/react/types/stitches'\nimport type { ElementCSS, WeaverseItemStore } from '@weaverse/core'\nimport clsx from 'clsx'\n\n// Make the css data formatted to correct order (desktop, tablet, mobile)\nfunction formatCSS(css: ElementCSS) {\n return {\n '@desktop': css['@desktop'],\n '@mobile': css['@mobile'],\n }\n}\n\nlet permanentClasses: Record<string, string> = {}\nexport function generateItemClassName(\n instance: WeaverseItemStore,\n stitchesInstance: Stitches\n) {\n let { css, type, className: cls = '' } = instance.data\n let className = ''\n let permanentClass = ''\n let perCss = instance.Element?.permanentCss\n if (perCss) {\n if (type in permanentClasses) {\n permanentClass = permanentClasses[type]\n } else {\n // @ts-expect-error\n let { className: perCls } = stitchesInstance.css(perCss)()\n Object.assign(permanentClasses, { [type]: perCls })\n permanentClass = perCls\n }\n }\n className = permanentClass\n if (css) {\n // let stitches create the style from css object and\n // then return the classname, so we can use it in the render\n let formattedCss = formatCSS(css)\n let newStitchesClass = stitchesInstance.css(formattedCss)().className || ''\n let { stitchesClass = '' } = instance\n let otherClass = (instance.ref.current?.className || '')\n .replace(stitchesClass, '')\n .replace(cls, '')\n .replace(permanentClass, '')\n .trim()\n className = clsx(permanentClass, cls, newStitchesClass, otherClass)\n instance.stitchesClass = newStitchesClass\n }\n return className\n}\n"],"mappings":"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","names":["import_react","routeKey","result","id","import_clsx","import_react","clsx","import_react","React","clsx"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/context.ts","../src/hooks.ts","../src/utils/data-connector.ts","../src/renderer.tsx","../src/utils/css.ts"],"sourcesContent":["export * from '@weaverse/core'\nexport * from './context'\nexport * from './hooks'\nexport * from './renderer'\nexport * from './types'\n","import type { Weaverse } from '@weaverse/core'\nimport { createContext } from 'react'\n\nexport let WeaverseContext = createContext<Weaverse>({} as Weaverse)\nexport let WeaverseContextProvider = WeaverseContext.Provider\nexport let WeaverseItemContext = createContext<{\n id: string\n parentId: string\n}>({ id: '', parentId: '' })\n","import { Weaverse, type WeaverseItemStore } from '@weaverse/core'\nimport { useContext } from 'react'\nimport { WeaverseContext, WeaverseItemContext } from '~/context'\n\n// Re-export the data connector utilities\nexport {\n replaceContentDataConnectors,\n replaceContentDataConnectorsDeep,\n} from './utils/data-connector'\n\nexport function useWeaverse<T = Weaverse>() {\n let weaverse = useContext(WeaverseContext)\n return weaverse as T\n}\n\nexport let useItemInstance = (id?: string) => {\n let { id: currentId } = useContext(WeaverseItemContext)\n let instance = Weaverse.itemInstances.get(id || currentId)\n if (!instance) {\n console.log(`Item instance ${id} not found`)\n return null\n }\n return instance as WeaverseItemStore\n}\n\nexport let useParentInstance = () => {\n let { parentId } = useContext(WeaverseItemContext)\n return useItemInstance(parentId || '')\n}\n\nexport let useChildInstances = (id?: string) => {\n let currentInstance = useItemInstance(id)\n if (!currentInstance) {\n return []\n }\n let { itemInstances } = Weaverse\n\n let {\n data: { children },\n } = currentInstance\n return children\n .map(({ id }: { id: string }) => itemInstances.get(id))\n .filter(Boolean) as WeaverseItemStore[]\n}\n","// Data connector utilities for replacing placeholders with real data\n// Generic data context type for flexible usage\nexport type DataContext = Record<string, unknown>\n\n// Cached regex pattern for better performance\nconst TEMPLATE_REGEX = /\\{\\{([^}]+)\\}\\}/g\nconst ARRAY_INDEX_REGEX = /^(\\w+)\\[(\\d+)\\]$/\n\n// Cache eviction ratio - remove oldest 25% when cache is full\nconst CACHE_EVICTION_RATIO = 0.25\n\n/**\n * Validates that a property name is safe to access (prevents prototype pollution)\n * Enhanced to handle route-specific patterns with special characters\n */\nfunction isSafePropertyName(key: string): boolean {\n // Block dangerous prototype pollution patterns\n const dangerousPatterns = ['__proto__', 'constructor', 'prototype']\n return !dangerousPatterns.includes(key)\n}\n\n/**\n * Parses a template path into route key and property path components\n * Handles complex routes like: routes/($locale).blogs.$blogHandle.$articleHandle\n * Enhanced with caching for improved performance\n *\n * @param path - The full path from template (e.g., \"routes/($locale)._index.weaverseData.page.name\")\n * @param dataContext - Available route data context\n * @returns Object with routeKey and propertyPath\n */\nfunction parseRouteAndProperty(\n path: string,\n dataContext: DataContext\n): {\n routeKey: string | null\n propertyPath: string\n} {\n if (!dataContext || typeof path !== 'string') {\n return { routeKey: null, propertyPath: path }\n }\n\n const trimmedPath = path.trim()\n\n // Create a cache key using stable hash instead of serializing route keys\n const dataHash = getDataContextHash(dataContext)\n const cacheKey = `${trimmedPath}::${dataHash}`\n\n // Check cache first\n const cachedResult = routeParsingCache.get(cacheKey)\n if (cachedResult) {\n // Update timestamp on cache hit\n cachedResult.timestamp = Date.now()\n return {\n routeKey: cachedResult.routeKey,\n propertyPath: cachedResult.propertyPath,\n }\n }\n\n // Get all available routes and sort by length (longest first for specificity)\n const availableRoutes = Object.keys(dataContext).sort(\n (a, b) => b.length - a.length\n )\n\n let result: { routeKey: string | null; propertyPath: string } = {\n routeKey: null,\n propertyPath: trimmedPath,\n }\n\n // Try to find the longest matching route key\n let found = false\n for (const routeKey of availableRoutes) {\n // Exact match\n if (trimmedPath === routeKey) {\n result = { routeKey, propertyPath: '' }\n found = true\n break\n }\n\n // Route key with property path\n if (trimmedPath.startsWith(`${routeKey}.`)) {\n const propertyPath = trimmedPath.substring(routeKey.length + 1)\n result = { routeKey, propertyPath }\n found = true\n break\n }\n }\n\n if (!found) {\n // No route key found, treat entire path as property path\n result = { routeKey: null, propertyPath: trimmedPath }\n }\n\n // Cache the result\n if (routeParsingCache.size >= ROUTE_PARSING_CACHE_MAX_SIZE) {\n // Clean cache by removing oldest entries\n const entries = Array.from(routeParsingCache.entries())\n entries.sort((a, b) => a[1].timestamp - b[1].timestamp)\n const toRemove = Math.floor(entries.length * CACHE_EVICTION_RATIO)\n for (let i = 0; i < toRemove; i++) {\n routeParsingCache.delete(entries[i][0])\n }\n }\n\n routeParsingCache.set(cacheKey, {\n routeKey: result.routeKey,\n propertyPath: result.propertyPath,\n timestamp: Date.now(),\n })\n\n return result\n}\n\n// Simple cache for parsed templates (max 100 entries)\nconst templateCache = new Map<string, string>()\nconst MAX_CACHE_SIZE = 100\n\n// Cache for fallback lookups to improve performance (moved to module level to prevent memory leaks)\nconst fallbackCache = new Map<\n string,\n { routeKey: string; value: unknown; timestamp: number }\n>()\nconst FALLBACK_CACHE_MAX_SIZE = 50\n\n// Route parsing cache for performance optimization\nconst routeParsingCache = new Map<\n string,\n { routeKey: string | null; propertyPath: string; timestamp: number }\n>()\nconst ROUTE_PARSING_CACHE_MAX_SIZE = 100\n\n// WeakMap for stable dataContext hashing - prevents repeated JSON.stringify\nconst dataContextHashCache = new WeakMap<object, string>()\nlet hashCounter = 0\n\n/**\n * Safely gets a nested value from an object using dot notation path\n * Supports array indexing with [index] syntax\n * @param obj - The object to traverse\n * @param path - Dot notation path (e.g., \"user.name\" or \"items[0].title\")\n * @param visited - Set to track visited objects for circular reference protection\n * @returns The resolved value or undefined if not found\n */\nfunction getNestedValue(\n obj: unknown,\n path: string,\n visited = new WeakSet()\n): unknown {\n return path.split('.').reduce((current, key) => {\n if (!current || typeof current !== 'object') {\n return\n }\n\n // Protect against circular references\n if (visited.has(current as WeakKey)) {\n console.warn('Circular reference detected in data connector path:', path)\n return\n }\n\n // Add to circular reference tracking\n visited.add(current as WeakKey)\n\n // Handle array indexing like items[0] or items[1]\n const arrayMatch = key.match(ARRAY_INDEX_REGEX)\n if (arrayMatch) {\n const [, arrayKey, index] = arrayMatch\n const arrayObj = (current as Record<string, unknown>)[arrayKey]\n if (Array.isArray(arrayObj)) {\n const indexNum = Number.parseInt(index, 10)\n if (indexNum >= 0 && indexNum < arrayObj.length) {\n return arrayObj[indexNum]\n }\n }\n return\n }\n\n // Handle regular object property access with security validation\n if (!isSafePropertyName(key)) {\n console.warn(`Unsafe property access attempted: ${key}`)\n return\n }\n\n return current !== null && key in current\n ? (current as Record<string, unknown>)[key]\n : undefined\n }, obj)\n}\n\n/**\n * Sanitizes a string value to prevent XSS attacks\n * @param value - The value to sanitize\n * @returns Sanitized string safe for HTML rendering\n */\nfunction sanitizeValue(value: unknown): string {\n if (value === null || value === undefined) {\n return ''\n }\n\n const stringValue = String(value)\n\n // Basic HTML entity encoding to prevent XSS\n return stringValue\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n .replace(/\\//g, '/')\n}\n\n/**\n * Creates a stable hash for dataContext object\n * Uses WeakMap to cache hash per object reference (no serialization needed)\n */\nfunction getDataContextHash(data: Record<string, unknown>): string {\n if (!dataContextHashCache.has(data)) {\n // Generate unique hash for this dataContext instance\n dataContextHashCache.set(data, `ctx_${++hashCounter}`)\n }\n const hash = dataContextHashCache.get(data)\n return hash || `ctx_${++hashCounter}`\n}\n\n/**\n * Creates a safe cache key from content and data\n * Uses stable hashing instead of JSON.stringify for massive performance gain\n */\nfunction createCacheKey(\n content: string,\n data: Record<string, unknown>\n): string {\n // Use stable hash instead of expensive JSON.stringify\n const dataHash = getDataContextHash(data)\n return `${content}:${dataHash}`\n}\n\n/**\n * Resolves data from the flat route-keyed data context\n * Enhanced to support complex route patterns with special characters\n * Supports: {{root.layout.shop.name}}, {{routes/($locale)._index.data}}, {{routes/($locale).blogs.$handle.$article.content}}\n */\nfunction resolveDataFromContext(\n path: string,\n dataContext: DataContext | null | undefined\n): unknown {\n if (!dataContext) {\n return\n }\n\n const trimmedPath = path.trim()\n\n // Use intelligent route parsing to separate route key from property path\n const { routeKey, propertyPath } = parseRouteAndProperty(\n trimmedPath,\n dataContext\n )\n\n // If we found a specific route key, resolve from that route's data\n if (routeKey && dataContext[routeKey]) {\n const routeData = dataContext[routeKey]\n if (typeof routeData === 'object' && routeData !== null) {\n if (propertyPath) {\n return getNestedValue(routeData, propertyPath)\n }\n return routeData\n }\n }\n\n // Fallback: search across all route data for backward compatibility\n // This handles cases like {{shop.name}} without route prefix\n\n // Check cache first\n const cachedResult = fallbackCache.get(trimmedPath)\n if (cachedResult && dataContext[cachedResult.routeKey]) {\n const value = getNestedValue(\n dataContext[cachedResult.routeKey],\n trimmedPath\n )\n if (value !== undefined) {\n // Update timestamp on cache hit\n cachedResult.timestamp = Date.now()\n return value\n }\n }\n\n // Search with priority order (most common routes first)\n const priorityRoutes = ['root', 'routes/product', 'routes/collection']\n const allRoutes = [\n ...priorityRoutes,\n ...Object.keys(dataContext).filter((k) => !priorityRoutes.includes(k)),\n ]\n\n for (const routeKey of allRoutes) {\n const routeData = dataContext[routeKey]\n if (routeData && typeof routeData === 'object' && routeData !== null) {\n const value = getNestedValue(routeData, trimmedPath)\n if (value !== undefined) {\n // Clean cache if it's getting too large\n if (fallbackCache.size >= FALLBACK_CACHE_MAX_SIZE) {\n const entries = Array.from(fallbackCache.entries())\n entries.sort((a, b) => a[1].timestamp - b[1].timestamp)\n // Remove oldest 25% of entries\n const toRemove = Math.floor(entries.length * CACHE_EVICTION_RATIO)\n for (let i = 0; i < toRemove; i++) {\n fallbackCache.delete(entries[i][0])\n }\n }\n fallbackCache.set(trimmedPath, {\n routeKey,\n value,\n timestamp: Date.now(),\n })\n return value\n }\n }\n }\n\n // Final fallback: try direct access (for non-route-keyed legacy data)\n return getNestedValue(dataContext, trimmedPath)\n}\n\n/**\n * Replaces data connector placeholders in content with actual values from data context\n * Supports {{path}} syntax with dot notation, array indexing, and route prefixes\n *\n * Enhanced syntax:\n * - {{root.siteSettings.title}} - Access root route data\n * - {{layout.navigation.items}} - Access layout route data\n * - {{parent.category.name}} - Access parent route data\n * - {{current.product.title}} - Access current route data\n * - {{user.name}} - Auto-resolved from combined data (backward compatible)\n *\n * @param content - The content string containing {{}} placeholders\n * @param dataContext - The enhanced WeaverseDataContext with route-keyed data\n * @returns The content with placeholders replaced by actual values\n */\nexport function replaceContentDataConnectors(\n content: string,\n dataContext: DataContext | null | undefined\n): string {\n if (!dataContext || typeof content !== 'string') {\n return content\n }\n\n try {\n // Simplified caching - dataContext is already the combined data\n const cacheKey = createCacheKey(content, dataContext)\n\n const cachedContent = templateCache.get(cacheKey)\n if (cachedContent) {\n return cachedContent\n }\n\n const newContent = content.replace(TEMPLATE_REGEX, (match, path) => {\n try {\n const value = resolveDataFromContext(path, dataContext)\n\n if (value === undefined || value === null) {\n return match // Return original placeholder if value not found\n }\n\n return sanitizeValue(value)\n } catch (pathError) {\n console.warn(\n `Error resolving data connector path \"${path}\":`,\n pathError\n )\n return match\n }\n })\n\n // Cache the result (with size limit)\n if (templateCache.size >= MAX_CACHE_SIZE) {\n const firstKey = templateCache.keys().next().value\n templateCache.delete(firstKey)\n }\n templateCache.set(cacheKey, newContent)\n\n return newContent\n } catch (error) {\n console.warn('Error processing data connectors:', error, { content })\n return content\n }\n}\n\n/**\n * Fast check if data contains any {{...}} placeholders\n * Returns true if any string value contains the pattern\n * This is MUCH faster than processing and allows early exit\n *\n * IMPORTANT: Uses global TEMPLATE_REGEX, must reset lastIndex\n */\nfunction hasPlaceholders(data: unknown, visited = new WeakSet()): boolean {\n if (typeof data === 'string') {\n // Reset regex state before testing to ensure consistent results\n TEMPLATE_REGEX.lastIndex = 0\n return TEMPLATE_REGEX.test(data)\n }\n\n if (typeof data !== 'object' || data === null) {\n return false\n }\n\n // Skip Date objects - they can't contain placeholders\n if (data instanceof Date) {\n return false\n }\n\n // Protect against circular references\n if (visited.has(data as WeakKey)) {\n return false\n }\n visited.add(data as WeakKey)\n\n try {\n if (Array.isArray(data)) {\n return data.some((item) => hasPlaceholders(item, visited))\n }\n\n // Check object values safely (skip property access errors)\n for (const key of Object.keys(data)) {\n try {\n const value = (data as Record<string, unknown>)[key]\n if (hasPlaceholders(value, visited)) {\n return true\n }\n } catch {\n // Ignore property access errors - continue checking other properties\n }\n }\n\n return false\n } finally {\n visited.delete(data as WeakKey)\n }\n}\n\n/**\n * Recursively replaces data connector placeholders in any data structure\n * IMMUTABLE: Creates deep copies during processing to avoid mutating original data\n * Handles strings, objects, arrays, and nested combinations\n *\n * PERFORMANCE: Now includes early exit if no placeholders detected\n *\n * @param data - The data to process (string, object, array, or primitive)\n * @param dataContext - The data context for replacements\n * @param visited - Set to track visited objects for circular reference protection\n * @param forceClone - Internal flag to force cloning even if no placeholders (for parent immutability)\n * @returns IMMUTABLE copy of the data with all string placeholders replaced\n */\nexport function replaceContentDataConnectorsDeep<T>(\n data: T,\n dataContext: DataContext | null | undefined,\n visited = new WeakSet(),\n forceClone = false\n): T {\n if (!dataContext) {\n return data\n }\n\n const dataHasPlaceholders = hasPlaceholders(data, new WeakSet())\n\n // PERFORMANCE: Fast check - if no placeholders exist and not forced to clone, skip ALL processing\n // This saves 90%+ of CPU time for components without data connectors\n if (!(dataHasPlaceholders || forceClone)) {\n return data\n }\n\n // Handle primitive types - no cloning needed for primitives\n if (typeof data === 'string') {\n return replaceContentDataConnectors(data, dataContext) as T\n }\n\n if (typeof data !== 'object' || data === null) {\n return data\n }\n\n // Protect against circular references\n if (visited.has(data as WeakKey)) {\n console.warn(\n 'Circular reference detected in deep data connector replacement'\n )\n return data\n }\n\n // Add to circular reference tracking\n visited.add(data as WeakKey)\n\n try {\n // Handle special objects that should be cloned as-is\n if (data instanceof Date) {\n // Date objects can't contain placeholders, but clone if forced (parent has placeholders)\n // or if somehow detected (shouldn't happen but be safe)\n if (forceClone || dataHasPlaceholders) {\n return new Date(data.getTime()) as T\n }\n return data\n }\n\n // Handle arrays - create new array with processed items\n // Force clone children if parent has placeholders (for immutability)\n if (Array.isArray(data)) {\n const result = data.map((item) =>\n replaceContentDataConnectorsDeep(\n item,\n dataContext,\n visited,\n dataHasPlaceholders\n )\n ) as T\n return result\n }\n\n // Handle plain objects - create new object with processed values\n // Force clone children if parent has placeholders (for immutability)\n const result = {} as T\n\n // Use Object.entries with try-catch per property to handle getter errors\n for (const key of Object.keys(data)) {\n try {\n const value = (data as Record<string, unknown>)[key]\n ;(result as Record<string, unknown>)[key] =\n replaceContentDataConnectorsDeep(\n value,\n dataContext,\n visited,\n dataHasPlaceholders\n )\n } catch (propertyError) {\n // If property access throws, skip it but continue processing\n console.warn(`Error accessing property \"${key}\":`, propertyError)\n // Don't include this property in result\n }\n }\n\n return result\n } catch (error) {\n console.warn('Error in deep data connector replacement:', error)\n return data\n } finally {\n // Remove from tracking when done processing this object\n visited.delete(data as WeakKey)\n }\n}\n","import clsx from 'clsx'\nimport React, { memo, useEffect, useRef } from 'react'\nimport { useItemInstance, useWeaverse } from '~/hooks'\nimport { WeaverseContextProvider, WeaverseItemContext } from './context'\nimport type { ItemComponentProps, WeaverseRootPropsType } from './types'\nimport { generateItemClassName } from './utils/css'\nimport { replaceContentDataConnectorsDeep } from './utils/data-connector'\n\nconst REACT_VERSION_THRESHOLD = 18\nconst reactVersion = Number(React.version?.split('.')[0]) || 0\n\n// Create a safe version of useSyncExternalStore that works in both client and server environments\nexport const useSafeExternalStore = (\n subscribe: any,\n getSnapshot: any,\n getServerSnapshot: any = getSnapshot\n) => {\n // In server environment or during SSR, just return the snapshot directly\n if (typeof window === 'undefined') {\n return getServerSnapshot()\n }\n\n // In client environment, use React.useSyncExternalStore if available (React 18+)\n if (React.useSyncExternalStore) {\n // biome-ignore lint/correctness/useHookAtTopLevel: <$>\n return React.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot)\n }\n\n // Fallback for older React versions - just return the current snapshot\n return getSnapshot()\n}\n\nexport const WeaverseRoot = memo(({ context }: WeaverseRootPropsType) => {\n const data = useSafeExternalStore(\n context.subscribe,\n context.getSnapShot,\n context.getSnapShot\n )\n const rootRef = useRef<HTMLElement>(null)\n\n useEffect(() => {\n context.contentRootElement = rootRef.current\n }, [context])\n\n const eventHandlers = context?.studioBridge?.eventHandlers || {}\n const themeClass = context.stitchesInstance.theme.className\n\n if (context.projectId) {\n return (\n <div\n className={`weaverse-content-root ${themeClass}`}\n {...eventHandlers}\n data-weaverse-project-id={context.projectId}\n data-weaverse-template-id={data.id}\n ref={rootRef}\n >\n <WeaverseContextProvider value={context}>\n <ItemInstance\n id={context.data.rootId || context.projectId}\n parentId={''}\n />\n </WeaverseContextProvider>\n </div>\n )\n }\n return null\n})\nWeaverseRoot.displayName = 'WeaverseRoot'\nconst ItemComponent = memo(({ instance }: ItemComponentProps) => {\n const context = useWeaverse()\n const { stitchesInstance, elementRegistry, platformType } = context\n const data = useSafeExternalStore(\n instance.subscribe,\n instance.getSnapShot,\n instance.getSnapShot\n )\n const {\n id,\n type,\n childIds = [],\n children = [],\n\n createdAt,\n updatedAt,\n deletedAt,\n css,\n __hidden,\n // Need to get rid of this `data` property\n data: _,\n ...rest\n } = data\n\n // Replace data connectors in all component data (handles strings, objects, and arrays recursively)\n // IMMUTABLE: Process the entire rest object to avoid mutating original content\n const processedRest = replaceContentDataConnectorsDeep(\n rest,\n context.dataContext\n )\n\n useEffect(() => {\n if (!instance.ref.current) {\n // Fallback `ref` if the element isn't created by `React.forwardRef`\n Object.assign(instance.ref, {\n current: document.querySelector(`[data-wv-id=\"${id}\"]`),\n })\n }\n }, [instance, id])\n\n if (__hidden) {\n return null\n }\n\n const Element = elementRegistry.get(type)\n\n if (Element?.Component) {\n const Component = Element.Component\n Component.displayName = type\n if (\n Component.$$typeof === Symbol.for('react.forward_ref') ||\n reactVersion > REACT_VERSION_THRESHOLD\n ) {\n processedRest.ref = instance.ref\n }\n const childItems = children?.length\n ? children\n : childIds?.length\n ? childIds.map((cid: string) => ({ id: cid }))\n : []\n\n const renderChildren = childItems.map(\n (item: { id: string }, index: number) => (\n <ItemInstance id={item.id} key={`${item.id}-${index}`} parentId={id} />\n )\n )\n\n return (\n <Component\n {...processedRest}\n children={renderChildren.length ? renderChildren : undefined}\n className={clsx(\n platformType !== 'shopify-hydrogen' &&\n generateItemClassName(instance, stitchesInstance),\n processedRest.data?.className\n )}\n data-wv-id={id}\n data-wv-type={type}\n key={id}\n />\n )\n }\n instance._store.deleted = true\n return null\n})\nItemComponent.displayName = 'WeaverseComponent'\n\nconst ItemInstance = memo(\n ({ id, parentId }: { id: string; parentId: string }) => {\n const instance = useItemInstance(id)\n if (!instance) {\n return <div style={{ display: 'none' }}>Item instance {id} not found</div>\n }\n return (\n <WeaverseItemContext.Provider value={{ parentId, id }}>\n <ItemComponent instance={instance} key={id} />\n </WeaverseItemContext.Provider>\n )\n }\n)\nItemInstance.displayName = 'WeaverseInstanceProvider'\n","import type Stitches from '@stitches/react/types/stitches'\nimport type { ElementCSS, WeaverseItemStore } from '@weaverse/core'\nimport clsx from 'clsx'\n\n// Make the css data formatted to correct order (desktop, tablet, mobile)\nfunction formatCSS(css: ElementCSS) {\n return {\n '@desktop': css['@desktop'],\n '@mobile': css['@mobile'],\n }\n}\n\nlet permanentClasses: Record<string, string> = {}\nexport function generateItemClassName(\n instance: WeaverseItemStore,\n stitchesInstance: Stitches\n) {\n let { css, type, className: cls = '' } = instance.data\n let className = ''\n let permanentClass = ''\n let perCss = instance.Element?.permanentCss\n if (perCss) {\n if (type in permanentClasses) {\n permanentClass = permanentClasses[type]\n } else {\n // @ts-expect-error\n let { className: perCls } = stitchesInstance.css(perCss)()\n Object.assign(permanentClasses, { [type]: perCls })\n permanentClass = perCls\n }\n }\n className = permanentClass\n if (css) {\n // let stitches create the style from css object and\n // then return the classname, so we can use it in the render\n let formattedCss = formatCSS(css)\n let newStitchesClass = stitchesInstance.css(formattedCss)().className || ''\n let { stitchesClass = '' } = instance\n let otherClass = (instance.ref.current?.className || '')\n .replace(stitchesClass, '')\n .replace(cls, '')\n .replace(permanentClass, '')\n .trim()\n className = clsx(permanentClass, cls, newStitchesClass, otherClass)\n instance.stitchesClass = newStitchesClass\n }\n return className\n}\n"],"mappings":"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","names":["import_react","routeKey","result","id","import_clsx","import_react","clsx","import_react","React","clsx"]}
|
package/dist/index.mjs
CHANGED
|
@@ -14,6 +14,7 @@ import { useContext } from "react";
|
|
|
14
14
|
// src/utils/data-connector.ts
|
|
15
15
|
var TEMPLATE_REGEX = /\{\{([^}]+)\}\}/g;
|
|
16
16
|
var ARRAY_INDEX_REGEX = /^(\w+)\[(\d+)\]$/;
|
|
17
|
+
var CACHE_EVICTION_RATIO = 0.25;
|
|
17
18
|
function isSafePropertyName(key) {
|
|
18
19
|
const dangerousPatterns = ["__proto__", "constructor", "prototype"];
|
|
19
20
|
return !dangerousPatterns.includes(key);
|
|
@@ -23,8 +24,8 @@ function parseRouteAndProperty(path, dataContext) {
|
|
|
23
24
|
return { routeKey: null, propertyPath: path };
|
|
24
25
|
}
|
|
25
26
|
const trimmedPath = path.trim();
|
|
26
|
-
const
|
|
27
|
-
const cacheKey = `${trimmedPath}::${
|
|
27
|
+
const dataHash = getDataContextHash(dataContext);
|
|
28
|
+
const cacheKey = `${trimmedPath}::${dataHash}`;
|
|
28
29
|
const cachedResult = routeParsingCache.get(cacheKey);
|
|
29
30
|
if (cachedResult) {
|
|
30
31
|
cachedResult.timestamp = Date.now();
|
|
@@ -47,7 +48,7 @@ function parseRouteAndProperty(path, dataContext) {
|
|
|
47
48
|
found = true;
|
|
48
49
|
break;
|
|
49
50
|
}
|
|
50
|
-
if (trimmedPath.startsWith(routeKey
|
|
51
|
+
if (trimmedPath.startsWith(`${routeKey}.`)) {
|
|
51
52
|
const propertyPath = trimmedPath.substring(routeKey.length + 1);
|
|
52
53
|
result = { routeKey, propertyPath };
|
|
53
54
|
found = true;
|
|
@@ -60,7 +61,7 @@ function parseRouteAndProperty(path, dataContext) {
|
|
|
60
61
|
if (routeParsingCache.size >= ROUTE_PARSING_CACHE_MAX_SIZE) {
|
|
61
62
|
const entries = Array.from(routeParsingCache.entries());
|
|
62
63
|
entries.sort((a, b) => a[1].timestamp - b[1].timestamp);
|
|
63
|
-
const toRemove = Math.floor(entries.length *
|
|
64
|
+
const toRemove = Math.floor(entries.length * CACHE_EVICTION_RATIO);
|
|
64
65
|
for (let i = 0; i < toRemove; i++) {
|
|
65
66
|
routeParsingCache.delete(entries[i][0]);
|
|
66
67
|
}
|
|
@@ -78,6 +79,8 @@ var fallbackCache = /* @__PURE__ */ new Map();
|
|
|
78
79
|
var FALLBACK_CACHE_MAX_SIZE = 50;
|
|
79
80
|
var routeParsingCache = /* @__PURE__ */ new Map();
|
|
80
81
|
var ROUTE_PARSING_CACHE_MAX_SIZE = 100;
|
|
82
|
+
var dataContextHashCache = /* @__PURE__ */ new WeakMap();
|
|
83
|
+
var hashCounter = 0;
|
|
81
84
|
function getNestedValue(obj, path, visited = /* @__PURE__ */ new WeakSet()) {
|
|
82
85
|
return path.split(".").reduce((current, key) => {
|
|
83
86
|
if (!current || typeof current !== "object") {
|
|
@@ -114,14 +117,16 @@ function sanitizeValue(value) {
|
|
|
114
117
|
const stringValue = String(value);
|
|
115
118
|
return stringValue.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'").replace(/\//g, "/");
|
|
116
119
|
}
|
|
117
|
-
function
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
return `${content}:${dataStr.slice(0, 100)}`;
|
|
121
|
-
} catch {
|
|
122
|
-
const keys = Object.keys(data).sort().join(",");
|
|
123
|
-
return `${content}:keys:${keys}`;
|
|
120
|
+
function getDataContextHash(data) {
|
|
121
|
+
if (!dataContextHashCache.has(data)) {
|
|
122
|
+
dataContextHashCache.set(data, `ctx_${++hashCounter}`);
|
|
124
123
|
}
|
|
124
|
+
const hash = dataContextHashCache.get(data);
|
|
125
|
+
return hash || `ctx_${++hashCounter}`;
|
|
126
|
+
}
|
|
127
|
+
function createCacheKey(content, data) {
|
|
128
|
+
const dataHash = getDataContextHash(data);
|
|
129
|
+
return `${content}:${dataHash}`;
|
|
125
130
|
}
|
|
126
131
|
function resolveDataFromContext(path, dataContext) {
|
|
127
132
|
if (!dataContext) {
|
|
@@ -165,7 +170,7 @@ function resolveDataFromContext(path, dataContext) {
|
|
|
165
170
|
if (fallbackCache.size >= FALLBACK_CACHE_MAX_SIZE) {
|
|
166
171
|
const entries = Array.from(fallbackCache.entries());
|
|
167
172
|
entries.sort((a, b) => a[1].timestamp - b[1].timestamp);
|
|
168
|
-
const toRemove = Math.floor(entries.length *
|
|
173
|
+
const toRemove = Math.floor(entries.length * CACHE_EVICTION_RATIO);
|
|
169
174
|
for (let i = 0; i < toRemove; i++) {
|
|
170
175
|
fallbackCache.delete(entries[i][0]);
|
|
171
176
|
}
|
|
@@ -187,8 +192,9 @@ function replaceContentDataConnectors(content, dataContext) {
|
|
|
187
192
|
}
|
|
188
193
|
try {
|
|
189
194
|
const cacheKey = createCacheKey(content, dataContext);
|
|
190
|
-
|
|
191
|
-
|
|
195
|
+
const cachedContent = templateCache.get(cacheKey);
|
|
196
|
+
if (cachedContent) {
|
|
197
|
+
return cachedContent;
|
|
192
198
|
}
|
|
193
199
|
const newContent = content.replace(TEMPLATE_REGEX, (match, path) => {
|
|
194
200
|
try {
|
|
@@ -216,10 +222,47 @@ function replaceContentDataConnectors(content, dataContext) {
|
|
|
216
222
|
return content;
|
|
217
223
|
}
|
|
218
224
|
}
|
|
219
|
-
function
|
|
225
|
+
function hasPlaceholders(data, visited = /* @__PURE__ */ new WeakSet()) {
|
|
226
|
+
if (typeof data === "string") {
|
|
227
|
+
TEMPLATE_REGEX.lastIndex = 0;
|
|
228
|
+
return TEMPLATE_REGEX.test(data);
|
|
229
|
+
}
|
|
230
|
+
if (typeof data !== "object" || data === null) {
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
if (data instanceof Date) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
if (visited.has(data)) {
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
visited.add(data);
|
|
240
|
+
try {
|
|
241
|
+
if (Array.isArray(data)) {
|
|
242
|
+
return data.some((item) => hasPlaceholders(item, visited));
|
|
243
|
+
}
|
|
244
|
+
for (const key of Object.keys(data)) {
|
|
245
|
+
try {
|
|
246
|
+
const value = data[key];
|
|
247
|
+
if (hasPlaceholders(value, visited)) {
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
} catch {
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return false;
|
|
254
|
+
} finally {
|
|
255
|
+
visited.delete(data);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
function replaceContentDataConnectorsDeep(data, dataContext, visited = /* @__PURE__ */ new WeakSet(), forceClone = false) {
|
|
220
259
|
if (!dataContext) {
|
|
221
260
|
return data;
|
|
222
261
|
}
|
|
262
|
+
const dataHasPlaceholders = hasPlaceholders(data, /* @__PURE__ */ new WeakSet());
|
|
263
|
+
if (!(dataHasPlaceholders || forceClone)) {
|
|
264
|
+
return data;
|
|
265
|
+
}
|
|
223
266
|
if (typeof data === "string") {
|
|
224
267
|
return replaceContentDataConnectors(data, dataContext);
|
|
225
268
|
}
|
|
@@ -235,18 +278,35 @@ function replaceContentDataConnectorsDeep(data, dataContext, visited = /* @__PUR
|
|
|
235
278
|
visited.add(data);
|
|
236
279
|
try {
|
|
237
280
|
if (data instanceof Date) {
|
|
238
|
-
|
|
281
|
+
if (forceClone || dataHasPlaceholders) {
|
|
282
|
+
return new Date(data.getTime());
|
|
283
|
+
}
|
|
284
|
+
return data;
|
|
239
285
|
}
|
|
240
286
|
if (Array.isArray(data)) {
|
|
241
287
|
const result2 = data.map(
|
|
242
|
-
(item) => replaceContentDataConnectorsDeep(
|
|
288
|
+
(item) => replaceContentDataConnectorsDeep(
|
|
289
|
+
item,
|
|
290
|
+
dataContext,
|
|
291
|
+
visited,
|
|
292
|
+
dataHasPlaceholders
|
|
293
|
+
)
|
|
243
294
|
);
|
|
244
295
|
return result2;
|
|
245
296
|
}
|
|
246
297
|
const result = {};
|
|
247
|
-
for (const
|
|
248
|
-
|
|
249
|
-
|
|
298
|
+
for (const key of Object.keys(data)) {
|
|
299
|
+
try {
|
|
300
|
+
const value = data[key];
|
|
301
|
+
result[key] = replaceContentDataConnectorsDeep(
|
|
302
|
+
value,
|
|
303
|
+
dataContext,
|
|
304
|
+
visited,
|
|
305
|
+
dataHasPlaceholders
|
|
306
|
+
);
|
|
307
|
+
} catch (propertyError) {
|
|
308
|
+
console.warn(`Error accessing property "${key}":`, propertyError);
|
|
309
|
+
}
|
|
250
310
|
}
|
|
251
311
|
return result;
|
|
252
312
|
} catch (error) {
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/context.ts","../src/hooks.ts","../src/utils/data-connector.ts","../src/renderer.tsx","../src/utils/css.ts"],"sourcesContent":["export * from '@weaverse/core'\nexport * from './context'\nexport * from './hooks'\nexport * from './renderer'\nexport * from './types'\n","import type { Weaverse } from '@weaverse/core'\nimport { createContext } from 'react'\n\nexport let WeaverseContext = createContext<Weaverse>({} as Weaverse)\nexport let WeaverseContextProvider = WeaverseContext.Provider\nexport let WeaverseItemContext = createContext<{\n id: string\n parentId: string\n}>({ id: '', parentId: '' })\n","import { Weaverse, type WeaverseItemStore } from '@weaverse/core'\nimport { useContext } from 'react'\nimport { WeaverseContext, WeaverseItemContext } from '~/context'\n\n// Re-export the data connector utilities\nexport {\n replaceContentDataConnectors,\n replaceContentDataConnectorsDeep,\n} from './utils/data-connector'\n\nexport function useWeaverse<T = Weaverse>() {\n let weaverse = useContext(WeaverseContext)\n return weaverse as T\n}\n\nexport let useItemInstance = (id?: string) => {\n let { id: currentId } = useContext(WeaverseItemContext)\n let instance = Weaverse.itemInstances.get(id || currentId)\n if (!instance) {\n console.log(`Item instance ${id} not found`)\n return null\n }\n return instance as WeaverseItemStore\n}\n\nexport let useParentInstance = () => {\n let { parentId } = useContext(WeaverseItemContext)\n return useItemInstance(parentId || '')\n}\n\nexport let useChildInstances = (id?: string) => {\n let currentInstance = useItemInstance(id)\n if (!currentInstance) {\n return []\n }\n let { itemInstances } = Weaverse\n\n let {\n data: { children },\n } = currentInstance\n return children\n .map(({ id }: { id: string }) => itemInstances.get(id))\n .filter(Boolean) as WeaverseItemStore[]\n}\n","// Data connector utilities for replacing placeholders with real data\n// Generic data context type for flexible usage\nexport type DataContext = Record<string, unknown>\n\n// Cached regex pattern for better performance\nconst TEMPLATE_REGEX = /\\{\\{([^}]+)\\}\\}/g\nconst ARRAY_INDEX_REGEX = /^(\\w+)\\[(\\d+)\\]$/\n\n/**\n * Validates that a property name is safe to access (prevents prototype pollution)\n * Enhanced to handle route-specific patterns with special characters\n */\nfunction isSafePropertyName(key: string): boolean {\n // Block dangerous prototype pollution patterns\n const dangerousPatterns = ['__proto__', 'constructor', 'prototype']\n return !dangerousPatterns.includes(key)\n}\n\n/**\n * Parses a template path into route key and property path components\n * Handles complex routes like: routes/($locale).blogs.$blogHandle.$articleHandle\n * Enhanced with caching for improved performance\n *\n * @param path - The full path from template (e.g., \"routes/($locale)._index.weaverseData.page.name\")\n * @param dataContext - Available route data context\n * @returns Object with routeKey and propertyPath\n */\nfunction parseRouteAndProperty(\n path: string,\n dataContext: DataContext\n): {\n routeKey: string | null\n propertyPath: string\n} {\n if (!dataContext || typeof path !== 'string') {\n return { routeKey: null, propertyPath: path }\n }\n\n const trimmedPath = path.trim()\n\n // Create a cache key that includes available routes for context awareness\n const availableRouteKeys = Object.keys(dataContext).sort().join('|')\n const cacheKey = `${trimmedPath}::${availableRouteKeys}`\n\n // Check cache first\n const cachedResult = routeParsingCache.get(cacheKey)\n if (cachedResult) {\n // Update timestamp on cache hit\n cachedResult.timestamp = Date.now()\n return {\n routeKey: cachedResult.routeKey,\n propertyPath: cachedResult.propertyPath,\n }\n }\n\n // Get all available routes and sort by length (longest first for specificity)\n const availableRoutes = Object.keys(dataContext).sort(\n (a, b) => b.length - a.length\n )\n\n let result: { routeKey: string | null; propertyPath: string } = {\n routeKey: null,\n propertyPath: trimmedPath,\n }\n\n // Try to find the longest matching route key\n let found = false\n for (const routeKey of availableRoutes) {\n // Exact match\n if (trimmedPath === routeKey) {\n result = { routeKey, propertyPath: '' }\n found = true\n break\n }\n\n // Route key with property path\n if (trimmedPath.startsWith(routeKey + '.')) {\n const propertyPath = trimmedPath.substring(routeKey.length + 1)\n result = { routeKey, propertyPath }\n found = true\n break\n }\n }\n\n if (!found) {\n // No route key found, treat entire path as property path\n result = { routeKey: null, propertyPath: trimmedPath }\n }\n\n // Cache the result\n if (routeParsingCache.size >= ROUTE_PARSING_CACHE_MAX_SIZE) {\n // Clean cache by removing oldest entries\n const entries = Array.from(routeParsingCache.entries())\n entries.sort((a, b) => a[1].timestamp - b[1].timestamp)\n const toRemove = Math.floor(entries.length * 0.25)\n for (let i = 0; i < toRemove; i++) {\n routeParsingCache.delete(entries[i][0])\n }\n }\n\n routeParsingCache.set(cacheKey, {\n routeKey: result.routeKey,\n propertyPath: result.propertyPath,\n timestamp: Date.now(),\n })\n\n return result\n}\n\n// Simple cache for parsed templates (max 100 entries)\nconst templateCache = new Map<string, string>()\nconst MAX_CACHE_SIZE = 100\n\n// Cache for fallback lookups to improve performance (moved to module level to prevent memory leaks)\nconst fallbackCache = new Map<\n string,\n { routeKey: string; value: unknown; timestamp: number }\n>()\nconst FALLBACK_CACHE_MAX_SIZE = 50\n\n// Route parsing cache for performance optimization\nconst routeParsingCache = new Map<\n string,\n { routeKey: string | null; propertyPath: string; timestamp: number }\n>()\nconst ROUTE_PARSING_CACHE_MAX_SIZE = 100\n\n/**\n * Safely gets a nested value from an object using dot notation path\n * Supports array indexing with [index] syntax\n * @param obj - The object to traverse\n * @param path - Dot notation path (e.g., \"user.name\" or \"items[0].title\")\n * @param visited - Set to track visited objects for circular reference protection\n * @returns The resolved value or undefined if not found\n */\nfunction getNestedValue(\n obj: unknown,\n path: string,\n visited = new WeakSet()\n): unknown {\n return path.split('.').reduce((current, key) => {\n if (!current || typeof current !== 'object') {\n return\n }\n\n // Protect against circular references\n if (visited.has(current as WeakKey)) {\n console.warn('Circular reference detected in data connector path:', path)\n return\n }\n\n // Add to circular reference tracking\n visited.add(current as WeakKey)\n\n // Handle array indexing like items[0] or items[1]\n const arrayMatch = key.match(ARRAY_INDEX_REGEX)\n if (arrayMatch) {\n const [, arrayKey, index] = arrayMatch\n const arrayObj = (current as Record<string, unknown>)[arrayKey]\n if (Array.isArray(arrayObj)) {\n const indexNum = Number.parseInt(index, 10)\n if (indexNum >= 0 && indexNum < arrayObj.length) {\n return arrayObj[indexNum]\n }\n }\n return\n }\n\n // Handle regular object property access with security validation\n if (!isSafePropertyName(key)) {\n console.warn(`Unsafe property access attempted: ${key}`)\n return\n }\n\n return current !== null && key in current\n ? (current as Record<string, unknown>)[key]\n : undefined\n }, obj)\n}\n\n/**\n * Sanitizes a string value to prevent XSS attacks\n * @param value - The value to sanitize\n * @returns Sanitized string safe for HTML rendering\n */\nfunction sanitizeValue(value: unknown): string {\n if (value === null || value === undefined) {\n return ''\n }\n\n const stringValue = String(value)\n\n // Basic HTML entity encoding to prevent XSS\n return stringValue\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n .replace(/\\//g, '/')\n}\n\n/**\n * Creates a safe cache key from content and data\n * Handles circular references by using a simplified approach\n */\nfunction createCacheKey(\n content: string,\n data: Record<string, unknown>\n): string {\n try {\n // Try a simple JSON stringification with a limit\n const dataStr = JSON.stringify(data)\n return `${content}:${dataStr.slice(0, 100)}`\n } catch {\n // If JSON.stringify fails (circular references), use a simpler approach\n const keys = Object.keys(data).sort().join(',')\n return `${content}:keys:${keys}`\n }\n}\n\n/**\n * Resolves data from the flat route-keyed data context\n * Enhanced to support complex route patterns with special characters\n * Supports: {{root.layout.shop.name}}, {{routes/($locale)._index.data}}, {{routes/($locale).blogs.$handle.$article.content}}\n */\nfunction resolveDataFromContext(\n path: string,\n dataContext: DataContext | null | undefined\n): unknown {\n if (!dataContext) {\n return\n }\n\n const trimmedPath = path.trim()\n\n // Use intelligent route parsing to separate route key from property path\n const { routeKey, propertyPath } = parseRouteAndProperty(\n trimmedPath,\n dataContext\n )\n\n // If we found a specific route key, resolve from that route's data\n if (routeKey && dataContext[routeKey]) {\n const routeData = dataContext[routeKey]\n if (typeof routeData === 'object' && routeData !== null) {\n if (propertyPath) {\n return getNestedValue(routeData, propertyPath)\n }\n return routeData\n }\n }\n\n // Fallback: search across all route data for backward compatibility\n // This handles cases like {{shop.name}} without route prefix\n\n // Check cache first\n const cachedResult = fallbackCache.get(trimmedPath)\n if (cachedResult && dataContext[cachedResult.routeKey]) {\n const value = getNestedValue(\n dataContext[cachedResult.routeKey],\n trimmedPath\n )\n if (value !== undefined) {\n // Update timestamp on cache hit\n cachedResult.timestamp = Date.now()\n return value\n }\n }\n\n // Search with priority order (most common routes first)\n const priorityRoutes = ['root', 'routes/product', 'routes/collection']\n const allRoutes = [\n ...priorityRoutes,\n ...Object.keys(dataContext).filter((k) => !priorityRoutes.includes(k)),\n ]\n\n for (const routeKey of allRoutes) {\n const routeData = dataContext[routeKey]\n if (routeData && typeof routeData === 'object' && routeData !== null) {\n const value = getNestedValue(routeData, trimmedPath)\n if (value !== undefined) {\n // Clean cache if it's getting too large\n if (fallbackCache.size >= FALLBACK_CACHE_MAX_SIZE) {\n const entries = Array.from(fallbackCache.entries())\n entries.sort((a, b) => a[1].timestamp - b[1].timestamp)\n // Remove oldest 25% of entries\n const toRemove = Math.floor(entries.length * 0.25)\n for (let i = 0; i < toRemove; i++) {\n fallbackCache.delete(entries[i][0])\n }\n }\n fallbackCache.set(trimmedPath, {\n routeKey,\n value,\n timestamp: Date.now(),\n })\n return value\n }\n }\n }\n\n // Final fallback: try direct access (for non-route-keyed legacy data)\n return getNestedValue(dataContext, trimmedPath)\n}\n\n/**\n * Replaces data connector placeholders in content with actual values from data context\n * Supports {{path}} syntax with dot notation, array indexing, and route prefixes\n *\n * Enhanced syntax:\n * - {{root.siteSettings.title}} - Access root route data\n * - {{layout.navigation.items}} - Access layout route data\n * - {{parent.category.name}} - Access parent route data\n * - {{current.product.title}} - Access current route data\n * - {{user.name}} - Auto-resolved from combined data (backward compatible)\n *\n * @param content - The content string containing {{}} placeholders\n * @param dataContext - The enhanced WeaverseDataContext with route-keyed data\n * @returns The content with placeholders replaced by actual values\n */\nexport function replaceContentDataConnectors(\n content: string,\n dataContext: DataContext | null | undefined\n): string {\n if (!dataContext || typeof content !== 'string') {\n return content\n }\n\n try {\n // Simplified caching - dataContext is already the combined data\n const cacheKey = createCacheKey(content, dataContext)\n\n if (templateCache.has(cacheKey)) {\n return templateCache.get(cacheKey)!\n }\n\n const newContent = content.replace(TEMPLATE_REGEX, (match, path) => {\n try {\n const value = resolveDataFromContext(path, dataContext)\n\n if (value === undefined || value === null) {\n return match // Return original placeholder if value not found\n }\n\n return sanitizeValue(value)\n } catch (pathError) {\n console.warn(\n `Error resolving data connector path \"${path}\":`,\n pathError\n )\n return match\n }\n })\n\n // Cache the result (with size limit)\n if (templateCache.size >= MAX_CACHE_SIZE) {\n const firstKey = templateCache.keys().next().value\n templateCache.delete(firstKey)\n }\n templateCache.set(cacheKey, newContent)\n\n return newContent\n } catch (error) {\n console.warn('Error processing data connectors:', error, { content })\n return content\n }\n}\n\n/**\n * Recursively replaces data connector placeholders in any data structure\n * IMMUTABLE: Creates deep copies during processing to avoid mutating original data\n * Handles strings, objects, arrays, and nested combinations\n *\n * @param data - The data to process (string, object, array, or primitive)\n * @param dataContext - The data context for replacements\n * @param visited - Set to track visited objects for circular reference protection\n * @returns IMMUTABLE copy of the data with all string placeholders replaced\n */\nexport function replaceContentDataConnectorsDeep<T>(\n data: T,\n dataContext: DataContext | null | undefined,\n visited = new WeakSet()\n): T {\n if (!dataContext) {\n return data\n }\n\n // Handle primitive types - no cloning needed for primitives\n if (typeof data === 'string') {\n return replaceContentDataConnectors(data, dataContext) as T\n }\n\n if (typeof data !== 'object' || data === null) {\n return data\n }\n\n // Protect against circular references\n if (visited.has(data as WeakKey)) {\n console.warn(\n 'Circular reference detected in deep data connector replacement'\n )\n return data\n }\n\n // Add to circular reference tracking\n visited.add(data as WeakKey)\n\n try {\n // Handle special objects that should be cloned as-is\n if (data instanceof Date) {\n return new Date(data.getTime()) as T\n }\n\n // Handle arrays - create new array with processed items\n if (Array.isArray(data)) {\n const result = data.map((item) =>\n replaceContentDataConnectorsDeep(item, dataContext, visited)\n ) as T\n return result\n }\n\n // Handle plain objects - create new object with processed values\n const result = {} as T\n for (const [key, value] of Object.entries(data)) {\n ;(result as Record<string, unknown>)[key] =\n replaceContentDataConnectorsDeep(value, dataContext, visited)\n }\n\n return result\n } catch (error) {\n console.warn('Error in deep data connector replacement:', error)\n return data\n } finally {\n // Remove from tracking when done processing this object\n visited.delete(data as WeakKey)\n }\n}\n","import clsx from 'clsx'\nimport React, { memo, useEffect, useRef } from 'react'\nimport { useItemInstance, useWeaverse } from '~/hooks'\nimport { WeaverseContextProvider, WeaverseItemContext } from './context'\nimport type { ItemComponentProps, WeaverseRootPropsType } from './types'\nimport { generateItemClassName } from './utils/css'\nimport { replaceContentDataConnectorsDeep } from './utils/data-connector'\n\nconst REACT_VERSION_THRESHOLD = 18\nconst reactVersion = Number(React.version?.split('.')[0]) || 0\n\n// Create a safe version of useSyncExternalStore that works in both client and server environments\nexport const useSafeExternalStore = (\n subscribe: any,\n getSnapshot: any,\n getServerSnapshot: any = getSnapshot\n) => {\n // In server environment or during SSR, just return the snapshot directly\n if (typeof window === 'undefined') {\n return getServerSnapshot()\n }\n\n // In client environment, use React.useSyncExternalStore if available (React 18+)\n if (React.useSyncExternalStore) {\n // biome-ignore lint/correctness/useHookAtTopLevel: <$>\n return React.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot)\n }\n\n // Fallback for older React versions - just return the current snapshot\n return getSnapshot()\n}\n\nexport const WeaverseRoot = memo(({ context }: WeaverseRootPropsType) => {\n const data = useSafeExternalStore(\n context.subscribe,\n context.getSnapShot,\n context.getSnapShot\n )\n const rootRef = useRef<HTMLElement>(null)\n\n useEffect(() => {\n context.contentRootElement = rootRef.current\n }, [context])\n\n const eventHandlers = context?.studioBridge?.eventHandlers || {}\n const themeClass = context.stitchesInstance.theme.className\n\n if (context.projectId) {\n return (\n <div\n className={`weaverse-content-root ${themeClass}`}\n {...eventHandlers}\n data-weaverse-project-id={context.projectId}\n data-weaverse-template-id={data.id}\n ref={rootRef}\n >\n <WeaverseContextProvider value={context}>\n <ItemInstance\n id={context.data.rootId || context.projectId}\n parentId={''}\n />\n </WeaverseContextProvider>\n </div>\n )\n }\n return null\n})\nWeaverseRoot.displayName = 'WeaverseRoot'\nconst ItemComponent = memo(({ instance }: ItemComponentProps) => {\n const context = useWeaverse()\n const { stitchesInstance, elementRegistry, platformType } = context\n const data = useSafeExternalStore(\n instance.subscribe,\n instance.getSnapShot,\n instance.getSnapShot\n )\n const {\n id,\n type,\n childIds = [],\n children = [],\n\n createdAt,\n updatedAt,\n deletedAt,\n css,\n __hidden,\n // Need to get rid of this `data` property\n data: _,\n ...rest\n } = data\n\n // Replace data connectors in all component data (handles strings, objects, and arrays recursively)\n // IMMUTABLE: Process the entire rest object to avoid mutating original content\n const processedRest = replaceContentDataConnectorsDeep(\n rest,\n context.dataContext\n )\n\n useEffect(() => {\n if (!instance.ref.current) {\n // Fallback `ref` if the element isn't created by `React.forwardRef`\n Object.assign(instance.ref, {\n current: document.querySelector(`[data-wv-id=\"${id}\"]`),\n })\n }\n }, [instance, id])\n\n if (__hidden) {\n return null\n }\n\n const Element = elementRegistry.get(type)\n\n if (Element?.Component) {\n const Component = Element.Component\n Component.displayName = type\n if (\n Component.$$typeof === Symbol.for('react.forward_ref') ||\n reactVersion > REACT_VERSION_THRESHOLD\n ) {\n processedRest.ref = instance.ref\n }\n const childItems = children?.length\n ? children\n : childIds?.length\n ? childIds.map((cid: string) => ({ id: cid }))\n : []\n\n const renderChildren = childItems.map(\n (item: { id: string }, index: number) => (\n <ItemInstance id={item.id} key={`${item.id}-${index}`} parentId={id} />\n )\n )\n\n return (\n <Component\n {...processedRest}\n children={renderChildren.length ? renderChildren : undefined}\n className={clsx(\n platformType !== 'shopify-hydrogen' &&\n generateItemClassName(instance, stitchesInstance),\n processedRest.data?.className\n )}\n data-wv-id={id}\n data-wv-type={type}\n key={id}\n />\n )\n }\n instance._store.deleted = true\n return null\n})\nItemComponent.displayName = 'WeaverseComponent'\n\nconst ItemInstance = memo(\n ({ id, parentId }: { id: string; parentId: string }) => {\n const instance = useItemInstance(id)\n if (!instance) {\n return <div style={{ display: 'none' }}>Item instance {id} not found</div>\n }\n return (\n <WeaverseItemContext.Provider value={{ parentId, id }}>\n <ItemComponent instance={instance} key={id} />\n </WeaverseItemContext.Provider>\n )\n }\n)\nItemInstance.displayName = 'WeaverseInstanceProvider'\n","import type Stitches from '@stitches/react/types/stitches'\nimport type { ElementCSS, WeaverseItemStore } from '@weaverse/core'\nimport clsx from 'clsx'\n\n// Make the css data formatted to correct order (desktop, tablet, mobile)\nfunction formatCSS(css: ElementCSS) {\n return {\n '@desktop': css['@desktop'],\n '@mobile': css['@mobile'],\n }\n}\n\nlet permanentClasses: Record<string, string> = {}\nexport function generateItemClassName(\n instance: WeaverseItemStore,\n stitchesInstance: Stitches\n) {\n let { css, type, className: cls = '' } = instance.data\n let className = ''\n let permanentClass = ''\n let perCss = instance.Element?.permanentCss\n if (perCss) {\n if (type in permanentClasses) {\n permanentClass = permanentClasses[type]\n } else {\n // @ts-expect-error\n let { className: perCls } = stitchesInstance.css(perCss)()\n Object.assign(permanentClasses, { [type]: perCls })\n permanentClass = perCls\n }\n }\n className = permanentClass\n if (css) {\n // let stitches create the style from css object and\n // then return the classname, so we can use it in the render\n let formattedCss = formatCSS(css)\n let newStitchesClass = stitchesInstance.css(formattedCss)().className || ''\n let { stitchesClass = '' } = instance\n let otherClass = (instance.ref.current?.className || '')\n .replace(stitchesClass, '')\n .replace(cls, '')\n .replace(permanentClass, '')\n .trim()\n className = clsx(permanentClass, cls, newStitchesClass, otherClass)\n instance.stitchesClass = newStitchesClass\n }\n return className\n}\n"],"mappings":"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","names":["routeKey","result","id","clsx","clsx"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/context.ts","../src/hooks.ts","../src/utils/data-connector.ts","../src/renderer.tsx","../src/utils/css.ts"],"sourcesContent":["export * from '@weaverse/core'\nexport * from './context'\nexport * from './hooks'\nexport * from './renderer'\nexport * from './types'\n","import type { Weaverse } from '@weaverse/core'\nimport { createContext } from 'react'\n\nexport let WeaverseContext = createContext<Weaverse>({} as Weaverse)\nexport let WeaverseContextProvider = WeaverseContext.Provider\nexport let WeaverseItemContext = createContext<{\n id: string\n parentId: string\n}>({ id: '', parentId: '' })\n","import { Weaverse, type WeaverseItemStore } from '@weaverse/core'\nimport { useContext } from 'react'\nimport { WeaverseContext, WeaverseItemContext } from '~/context'\n\n// Re-export the data connector utilities\nexport {\n replaceContentDataConnectors,\n replaceContentDataConnectorsDeep,\n} from './utils/data-connector'\n\nexport function useWeaverse<T = Weaverse>() {\n let weaverse = useContext(WeaverseContext)\n return weaverse as T\n}\n\nexport let useItemInstance = (id?: string) => {\n let { id: currentId } = useContext(WeaverseItemContext)\n let instance = Weaverse.itemInstances.get(id || currentId)\n if (!instance) {\n console.log(`Item instance ${id} not found`)\n return null\n }\n return instance as WeaverseItemStore\n}\n\nexport let useParentInstance = () => {\n let { parentId } = useContext(WeaverseItemContext)\n return useItemInstance(parentId || '')\n}\n\nexport let useChildInstances = (id?: string) => {\n let currentInstance = useItemInstance(id)\n if (!currentInstance) {\n return []\n }\n let { itemInstances } = Weaverse\n\n let {\n data: { children },\n } = currentInstance\n return children\n .map(({ id }: { id: string }) => itemInstances.get(id))\n .filter(Boolean) as WeaverseItemStore[]\n}\n","// Data connector utilities for replacing placeholders with real data\n// Generic data context type for flexible usage\nexport type DataContext = Record<string, unknown>\n\n// Cached regex pattern for better performance\nconst TEMPLATE_REGEX = /\\{\\{([^}]+)\\}\\}/g\nconst ARRAY_INDEX_REGEX = /^(\\w+)\\[(\\d+)\\]$/\n\n// Cache eviction ratio - remove oldest 25% when cache is full\nconst CACHE_EVICTION_RATIO = 0.25\n\n/**\n * Validates that a property name is safe to access (prevents prototype pollution)\n * Enhanced to handle route-specific patterns with special characters\n */\nfunction isSafePropertyName(key: string): boolean {\n // Block dangerous prototype pollution patterns\n const dangerousPatterns = ['__proto__', 'constructor', 'prototype']\n return !dangerousPatterns.includes(key)\n}\n\n/**\n * Parses a template path into route key and property path components\n * Handles complex routes like: routes/($locale).blogs.$blogHandle.$articleHandle\n * Enhanced with caching for improved performance\n *\n * @param path - The full path from template (e.g., \"routes/($locale)._index.weaverseData.page.name\")\n * @param dataContext - Available route data context\n * @returns Object with routeKey and propertyPath\n */\nfunction parseRouteAndProperty(\n path: string,\n dataContext: DataContext\n): {\n routeKey: string | null\n propertyPath: string\n} {\n if (!dataContext || typeof path !== 'string') {\n return { routeKey: null, propertyPath: path }\n }\n\n const trimmedPath = path.trim()\n\n // Create a cache key using stable hash instead of serializing route keys\n const dataHash = getDataContextHash(dataContext)\n const cacheKey = `${trimmedPath}::${dataHash}`\n\n // Check cache first\n const cachedResult = routeParsingCache.get(cacheKey)\n if (cachedResult) {\n // Update timestamp on cache hit\n cachedResult.timestamp = Date.now()\n return {\n routeKey: cachedResult.routeKey,\n propertyPath: cachedResult.propertyPath,\n }\n }\n\n // Get all available routes and sort by length (longest first for specificity)\n const availableRoutes = Object.keys(dataContext).sort(\n (a, b) => b.length - a.length\n )\n\n let result: { routeKey: string | null; propertyPath: string } = {\n routeKey: null,\n propertyPath: trimmedPath,\n }\n\n // Try to find the longest matching route key\n let found = false\n for (const routeKey of availableRoutes) {\n // Exact match\n if (trimmedPath === routeKey) {\n result = { routeKey, propertyPath: '' }\n found = true\n break\n }\n\n // Route key with property path\n if (trimmedPath.startsWith(`${routeKey}.`)) {\n const propertyPath = trimmedPath.substring(routeKey.length + 1)\n result = { routeKey, propertyPath }\n found = true\n break\n }\n }\n\n if (!found) {\n // No route key found, treat entire path as property path\n result = { routeKey: null, propertyPath: trimmedPath }\n }\n\n // Cache the result\n if (routeParsingCache.size >= ROUTE_PARSING_CACHE_MAX_SIZE) {\n // Clean cache by removing oldest entries\n const entries = Array.from(routeParsingCache.entries())\n entries.sort((a, b) => a[1].timestamp - b[1].timestamp)\n const toRemove = Math.floor(entries.length * CACHE_EVICTION_RATIO)\n for (let i = 0; i < toRemove; i++) {\n routeParsingCache.delete(entries[i][0])\n }\n }\n\n routeParsingCache.set(cacheKey, {\n routeKey: result.routeKey,\n propertyPath: result.propertyPath,\n timestamp: Date.now(),\n })\n\n return result\n}\n\n// Simple cache for parsed templates (max 100 entries)\nconst templateCache = new Map<string, string>()\nconst MAX_CACHE_SIZE = 100\n\n// Cache for fallback lookups to improve performance (moved to module level to prevent memory leaks)\nconst fallbackCache = new Map<\n string,\n { routeKey: string; value: unknown; timestamp: number }\n>()\nconst FALLBACK_CACHE_MAX_SIZE = 50\n\n// Route parsing cache for performance optimization\nconst routeParsingCache = new Map<\n string,\n { routeKey: string | null; propertyPath: string; timestamp: number }\n>()\nconst ROUTE_PARSING_CACHE_MAX_SIZE = 100\n\n// WeakMap for stable dataContext hashing - prevents repeated JSON.stringify\nconst dataContextHashCache = new WeakMap<object, string>()\nlet hashCounter = 0\n\n/**\n * Safely gets a nested value from an object using dot notation path\n * Supports array indexing with [index] syntax\n * @param obj - The object to traverse\n * @param path - Dot notation path (e.g., \"user.name\" or \"items[0].title\")\n * @param visited - Set to track visited objects for circular reference protection\n * @returns The resolved value or undefined if not found\n */\nfunction getNestedValue(\n obj: unknown,\n path: string,\n visited = new WeakSet()\n): unknown {\n return path.split('.').reduce((current, key) => {\n if (!current || typeof current !== 'object') {\n return\n }\n\n // Protect against circular references\n if (visited.has(current as WeakKey)) {\n console.warn('Circular reference detected in data connector path:', path)\n return\n }\n\n // Add to circular reference tracking\n visited.add(current as WeakKey)\n\n // Handle array indexing like items[0] or items[1]\n const arrayMatch = key.match(ARRAY_INDEX_REGEX)\n if (arrayMatch) {\n const [, arrayKey, index] = arrayMatch\n const arrayObj = (current as Record<string, unknown>)[arrayKey]\n if (Array.isArray(arrayObj)) {\n const indexNum = Number.parseInt(index, 10)\n if (indexNum >= 0 && indexNum < arrayObj.length) {\n return arrayObj[indexNum]\n }\n }\n return\n }\n\n // Handle regular object property access with security validation\n if (!isSafePropertyName(key)) {\n console.warn(`Unsafe property access attempted: ${key}`)\n return\n }\n\n return current !== null && key in current\n ? (current as Record<string, unknown>)[key]\n : undefined\n }, obj)\n}\n\n/**\n * Sanitizes a string value to prevent XSS attacks\n * @param value - The value to sanitize\n * @returns Sanitized string safe for HTML rendering\n */\nfunction sanitizeValue(value: unknown): string {\n if (value === null || value === undefined) {\n return ''\n }\n\n const stringValue = String(value)\n\n // Basic HTML entity encoding to prevent XSS\n return stringValue\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n .replace(/\\//g, '/')\n}\n\n/**\n * Creates a stable hash for dataContext object\n * Uses WeakMap to cache hash per object reference (no serialization needed)\n */\nfunction getDataContextHash(data: Record<string, unknown>): string {\n if (!dataContextHashCache.has(data)) {\n // Generate unique hash for this dataContext instance\n dataContextHashCache.set(data, `ctx_${++hashCounter}`)\n }\n const hash = dataContextHashCache.get(data)\n return hash || `ctx_${++hashCounter}`\n}\n\n/**\n * Creates a safe cache key from content and data\n * Uses stable hashing instead of JSON.stringify for massive performance gain\n */\nfunction createCacheKey(\n content: string,\n data: Record<string, unknown>\n): string {\n // Use stable hash instead of expensive JSON.stringify\n const dataHash = getDataContextHash(data)\n return `${content}:${dataHash}`\n}\n\n/**\n * Resolves data from the flat route-keyed data context\n * Enhanced to support complex route patterns with special characters\n * Supports: {{root.layout.shop.name}}, {{routes/($locale)._index.data}}, {{routes/($locale).blogs.$handle.$article.content}}\n */\nfunction resolveDataFromContext(\n path: string,\n dataContext: DataContext | null | undefined\n): unknown {\n if (!dataContext) {\n return\n }\n\n const trimmedPath = path.trim()\n\n // Use intelligent route parsing to separate route key from property path\n const { routeKey, propertyPath } = parseRouteAndProperty(\n trimmedPath,\n dataContext\n )\n\n // If we found a specific route key, resolve from that route's data\n if (routeKey && dataContext[routeKey]) {\n const routeData = dataContext[routeKey]\n if (typeof routeData === 'object' && routeData !== null) {\n if (propertyPath) {\n return getNestedValue(routeData, propertyPath)\n }\n return routeData\n }\n }\n\n // Fallback: search across all route data for backward compatibility\n // This handles cases like {{shop.name}} without route prefix\n\n // Check cache first\n const cachedResult = fallbackCache.get(trimmedPath)\n if (cachedResult && dataContext[cachedResult.routeKey]) {\n const value = getNestedValue(\n dataContext[cachedResult.routeKey],\n trimmedPath\n )\n if (value !== undefined) {\n // Update timestamp on cache hit\n cachedResult.timestamp = Date.now()\n return value\n }\n }\n\n // Search with priority order (most common routes first)\n const priorityRoutes = ['root', 'routes/product', 'routes/collection']\n const allRoutes = [\n ...priorityRoutes,\n ...Object.keys(dataContext).filter((k) => !priorityRoutes.includes(k)),\n ]\n\n for (const routeKey of allRoutes) {\n const routeData = dataContext[routeKey]\n if (routeData && typeof routeData === 'object' && routeData !== null) {\n const value = getNestedValue(routeData, trimmedPath)\n if (value !== undefined) {\n // Clean cache if it's getting too large\n if (fallbackCache.size >= FALLBACK_CACHE_MAX_SIZE) {\n const entries = Array.from(fallbackCache.entries())\n entries.sort((a, b) => a[1].timestamp - b[1].timestamp)\n // Remove oldest 25% of entries\n const toRemove = Math.floor(entries.length * CACHE_EVICTION_RATIO)\n for (let i = 0; i < toRemove; i++) {\n fallbackCache.delete(entries[i][0])\n }\n }\n fallbackCache.set(trimmedPath, {\n routeKey,\n value,\n timestamp: Date.now(),\n })\n return value\n }\n }\n }\n\n // Final fallback: try direct access (for non-route-keyed legacy data)\n return getNestedValue(dataContext, trimmedPath)\n}\n\n/**\n * Replaces data connector placeholders in content with actual values from data context\n * Supports {{path}} syntax with dot notation, array indexing, and route prefixes\n *\n * Enhanced syntax:\n * - {{root.siteSettings.title}} - Access root route data\n * - {{layout.navigation.items}} - Access layout route data\n * - {{parent.category.name}} - Access parent route data\n * - {{current.product.title}} - Access current route data\n * - {{user.name}} - Auto-resolved from combined data (backward compatible)\n *\n * @param content - The content string containing {{}} placeholders\n * @param dataContext - The enhanced WeaverseDataContext with route-keyed data\n * @returns The content with placeholders replaced by actual values\n */\nexport function replaceContentDataConnectors(\n content: string,\n dataContext: DataContext | null | undefined\n): string {\n if (!dataContext || typeof content !== 'string') {\n return content\n }\n\n try {\n // Simplified caching - dataContext is already the combined data\n const cacheKey = createCacheKey(content, dataContext)\n\n const cachedContent = templateCache.get(cacheKey)\n if (cachedContent) {\n return cachedContent\n }\n\n const newContent = content.replace(TEMPLATE_REGEX, (match, path) => {\n try {\n const value = resolveDataFromContext(path, dataContext)\n\n if (value === undefined || value === null) {\n return match // Return original placeholder if value not found\n }\n\n return sanitizeValue(value)\n } catch (pathError) {\n console.warn(\n `Error resolving data connector path \"${path}\":`,\n pathError\n )\n return match\n }\n })\n\n // Cache the result (with size limit)\n if (templateCache.size >= MAX_CACHE_SIZE) {\n const firstKey = templateCache.keys().next().value\n templateCache.delete(firstKey)\n }\n templateCache.set(cacheKey, newContent)\n\n return newContent\n } catch (error) {\n console.warn('Error processing data connectors:', error, { content })\n return content\n }\n}\n\n/**\n * Fast check if data contains any {{...}} placeholders\n * Returns true if any string value contains the pattern\n * This is MUCH faster than processing and allows early exit\n *\n * IMPORTANT: Uses global TEMPLATE_REGEX, must reset lastIndex\n */\nfunction hasPlaceholders(data: unknown, visited = new WeakSet()): boolean {\n if (typeof data === 'string') {\n // Reset regex state before testing to ensure consistent results\n TEMPLATE_REGEX.lastIndex = 0\n return TEMPLATE_REGEX.test(data)\n }\n\n if (typeof data !== 'object' || data === null) {\n return false\n }\n\n // Skip Date objects - they can't contain placeholders\n if (data instanceof Date) {\n return false\n }\n\n // Protect against circular references\n if (visited.has(data as WeakKey)) {\n return false\n }\n visited.add(data as WeakKey)\n\n try {\n if (Array.isArray(data)) {\n return data.some((item) => hasPlaceholders(item, visited))\n }\n\n // Check object values safely (skip property access errors)\n for (const key of Object.keys(data)) {\n try {\n const value = (data as Record<string, unknown>)[key]\n if (hasPlaceholders(value, visited)) {\n return true\n }\n } catch {\n // Ignore property access errors - continue checking other properties\n }\n }\n\n return false\n } finally {\n visited.delete(data as WeakKey)\n }\n}\n\n/**\n * Recursively replaces data connector placeholders in any data structure\n * IMMUTABLE: Creates deep copies during processing to avoid mutating original data\n * Handles strings, objects, arrays, and nested combinations\n *\n * PERFORMANCE: Now includes early exit if no placeholders detected\n *\n * @param data - The data to process (string, object, array, or primitive)\n * @param dataContext - The data context for replacements\n * @param visited - Set to track visited objects for circular reference protection\n * @param forceClone - Internal flag to force cloning even if no placeholders (for parent immutability)\n * @returns IMMUTABLE copy of the data with all string placeholders replaced\n */\nexport function replaceContentDataConnectorsDeep<T>(\n data: T,\n dataContext: DataContext | null | undefined,\n visited = new WeakSet(),\n forceClone = false\n): T {\n if (!dataContext) {\n return data\n }\n\n const dataHasPlaceholders = hasPlaceholders(data, new WeakSet())\n\n // PERFORMANCE: Fast check - if no placeholders exist and not forced to clone, skip ALL processing\n // This saves 90%+ of CPU time for components without data connectors\n if (!(dataHasPlaceholders || forceClone)) {\n return data\n }\n\n // Handle primitive types - no cloning needed for primitives\n if (typeof data === 'string') {\n return replaceContentDataConnectors(data, dataContext) as T\n }\n\n if (typeof data !== 'object' || data === null) {\n return data\n }\n\n // Protect against circular references\n if (visited.has(data as WeakKey)) {\n console.warn(\n 'Circular reference detected in deep data connector replacement'\n )\n return data\n }\n\n // Add to circular reference tracking\n visited.add(data as WeakKey)\n\n try {\n // Handle special objects that should be cloned as-is\n if (data instanceof Date) {\n // Date objects can't contain placeholders, but clone if forced (parent has placeholders)\n // or if somehow detected (shouldn't happen but be safe)\n if (forceClone || dataHasPlaceholders) {\n return new Date(data.getTime()) as T\n }\n return data\n }\n\n // Handle arrays - create new array with processed items\n // Force clone children if parent has placeholders (for immutability)\n if (Array.isArray(data)) {\n const result = data.map((item) =>\n replaceContentDataConnectorsDeep(\n item,\n dataContext,\n visited,\n dataHasPlaceholders\n )\n ) as T\n return result\n }\n\n // Handle plain objects - create new object with processed values\n // Force clone children if parent has placeholders (for immutability)\n const result = {} as T\n\n // Use Object.entries with try-catch per property to handle getter errors\n for (const key of Object.keys(data)) {\n try {\n const value = (data as Record<string, unknown>)[key]\n ;(result as Record<string, unknown>)[key] =\n replaceContentDataConnectorsDeep(\n value,\n dataContext,\n visited,\n dataHasPlaceholders\n )\n } catch (propertyError) {\n // If property access throws, skip it but continue processing\n console.warn(`Error accessing property \"${key}\":`, propertyError)\n // Don't include this property in result\n }\n }\n\n return result\n } catch (error) {\n console.warn('Error in deep data connector replacement:', error)\n return data\n } finally {\n // Remove from tracking when done processing this object\n visited.delete(data as WeakKey)\n }\n}\n","import clsx from 'clsx'\nimport React, { memo, useEffect, useRef } from 'react'\nimport { useItemInstance, useWeaverse } from '~/hooks'\nimport { WeaverseContextProvider, WeaverseItemContext } from './context'\nimport type { ItemComponentProps, WeaverseRootPropsType } from './types'\nimport { generateItemClassName } from './utils/css'\nimport { replaceContentDataConnectorsDeep } from './utils/data-connector'\n\nconst REACT_VERSION_THRESHOLD = 18\nconst reactVersion = Number(React.version?.split('.')[0]) || 0\n\n// Create a safe version of useSyncExternalStore that works in both client and server environments\nexport const useSafeExternalStore = (\n subscribe: any,\n getSnapshot: any,\n getServerSnapshot: any = getSnapshot\n) => {\n // In server environment or during SSR, just return the snapshot directly\n if (typeof window === 'undefined') {\n return getServerSnapshot()\n }\n\n // In client environment, use React.useSyncExternalStore if available (React 18+)\n if (React.useSyncExternalStore) {\n // biome-ignore lint/correctness/useHookAtTopLevel: <$>\n return React.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot)\n }\n\n // Fallback for older React versions - just return the current snapshot\n return getSnapshot()\n}\n\nexport const WeaverseRoot = memo(({ context }: WeaverseRootPropsType) => {\n const data = useSafeExternalStore(\n context.subscribe,\n context.getSnapShot,\n context.getSnapShot\n )\n const rootRef = useRef<HTMLElement>(null)\n\n useEffect(() => {\n context.contentRootElement = rootRef.current\n }, [context])\n\n const eventHandlers = context?.studioBridge?.eventHandlers || {}\n const themeClass = context.stitchesInstance.theme.className\n\n if (context.projectId) {\n return (\n <div\n className={`weaverse-content-root ${themeClass}`}\n {...eventHandlers}\n data-weaverse-project-id={context.projectId}\n data-weaverse-template-id={data.id}\n ref={rootRef}\n >\n <WeaverseContextProvider value={context}>\n <ItemInstance\n id={context.data.rootId || context.projectId}\n parentId={''}\n />\n </WeaverseContextProvider>\n </div>\n )\n }\n return null\n})\nWeaverseRoot.displayName = 'WeaverseRoot'\nconst ItemComponent = memo(({ instance }: ItemComponentProps) => {\n const context = useWeaverse()\n const { stitchesInstance, elementRegistry, platformType } = context\n const data = useSafeExternalStore(\n instance.subscribe,\n instance.getSnapShot,\n instance.getSnapShot\n )\n const {\n id,\n type,\n childIds = [],\n children = [],\n\n createdAt,\n updatedAt,\n deletedAt,\n css,\n __hidden,\n // Need to get rid of this `data` property\n data: _,\n ...rest\n } = data\n\n // Replace data connectors in all component data (handles strings, objects, and arrays recursively)\n // IMMUTABLE: Process the entire rest object to avoid mutating original content\n const processedRest = replaceContentDataConnectorsDeep(\n rest,\n context.dataContext\n )\n\n useEffect(() => {\n if (!instance.ref.current) {\n // Fallback `ref` if the element isn't created by `React.forwardRef`\n Object.assign(instance.ref, {\n current: document.querySelector(`[data-wv-id=\"${id}\"]`),\n })\n }\n }, [instance, id])\n\n if (__hidden) {\n return null\n }\n\n const Element = elementRegistry.get(type)\n\n if (Element?.Component) {\n const Component = Element.Component\n Component.displayName = type\n if (\n Component.$$typeof === Symbol.for('react.forward_ref') ||\n reactVersion > REACT_VERSION_THRESHOLD\n ) {\n processedRest.ref = instance.ref\n }\n const childItems = children?.length\n ? children\n : childIds?.length\n ? childIds.map((cid: string) => ({ id: cid }))\n : []\n\n const renderChildren = childItems.map(\n (item: { id: string }, index: number) => (\n <ItemInstance id={item.id} key={`${item.id}-${index}`} parentId={id} />\n )\n )\n\n return (\n <Component\n {...processedRest}\n children={renderChildren.length ? renderChildren : undefined}\n className={clsx(\n platformType !== 'shopify-hydrogen' &&\n generateItemClassName(instance, stitchesInstance),\n processedRest.data?.className\n )}\n data-wv-id={id}\n data-wv-type={type}\n key={id}\n />\n )\n }\n instance._store.deleted = true\n return null\n})\nItemComponent.displayName = 'WeaverseComponent'\n\nconst ItemInstance = memo(\n ({ id, parentId }: { id: string; parentId: string }) => {\n const instance = useItemInstance(id)\n if (!instance) {\n return <div style={{ display: 'none' }}>Item instance {id} not found</div>\n }\n return (\n <WeaverseItemContext.Provider value={{ parentId, id }}>\n <ItemComponent instance={instance} key={id} />\n </WeaverseItemContext.Provider>\n )\n }\n)\nItemInstance.displayName = 'WeaverseInstanceProvider'\n","import type Stitches from '@stitches/react/types/stitches'\nimport type { ElementCSS, WeaverseItemStore } from '@weaverse/core'\nimport clsx from 'clsx'\n\n// Make the css data formatted to correct order (desktop, tablet, mobile)\nfunction formatCSS(css: ElementCSS) {\n return {\n '@desktop': css['@desktop'],\n '@mobile': css['@mobile'],\n }\n}\n\nlet permanentClasses: Record<string, string> = {}\nexport function generateItemClassName(\n instance: WeaverseItemStore,\n stitchesInstance: Stitches\n) {\n let { css, type, className: cls = '' } = instance.data\n let className = ''\n let permanentClass = ''\n let perCss = instance.Element?.permanentCss\n if (perCss) {\n if (type in permanentClasses) {\n permanentClass = permanentClasses[type]\n } else {\n // @ts-expect-error\n let { className: perCls } = stitchesInstance.css(perCss)()\n Object.assign(permanentClasses, { [type]: perCls })\n permanentClass = perCls\n }\n }\n className = permanentClass\n if (css) {\n // let stitches create the style from css object and\n // then return the classname, so we can use it in the render\n let formattedCss = formatCSS(css)\n let newStitchesClass = stitchesInstance.css(formattedCss)().className || ''\n let { stitchesClass = '' } = instance\n let otherClass = (instance.ref.current?.className || '')\n .replace(stitchesClass, '')\n .replace(cls, '')\n .replace(permanentClass, '')\n .trim()\n className = clsx(permanentClass, cls, newStitchesClass, otherClass)\n instance.stitchesClass = newStitchesClass\n }\n return className\n}\n"],"mappings":"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","names":["routeKey","result","id","clsx","clsx"]}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@weaverse/react",
|
|
3
3
|
"author": "Weaverse Team",
|
|
4
4
|
"description": "React bindings for Weaverse",
|
|
5
|
-
"version": "5.5.
|
|
5
|
+
"version": "5.5.1",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"typings": "dist/index.d.ts",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"outDir": "dist"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@weaverse/core": "5.5.
|
|
45
|
+
"@weaverse/core": "5.5.1",
|
|
46
46
|
"clsx": "^2.1.1",
|
|
47
47
|
"react": ">=18",
|
|
48
48
|
"react-dom": ">=18"
|