rwsdk 0.2.0-alpha.16-test.20250825032050 → 0.2.0-alpha.18

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.
@@ -28,23 +28,18 @@ function hasJsxFunctions(text) {
28
28
  text.includes('jsxDEV("link"') ||
29
29
  text.includes("jsxDEV('link'"));
30
30
  }
31
- // Transform import statements in script content using ts-morph
32
31
  function transformScriptImports(scriptContent, manifest) {
33
32
  const scriptProject = new Project({ useInMemoryFileSystem: true });
34
33
  try {
35
- // Wrap in a function to make it valid JavaScript
36
34
  const wrappedContent = `function __wrapper() {${scriptContent}}`;
37
35
  const scriptFile = scriptProject.createSourceFile("script.js", wrappedContent);
38
36
  let hasChanges = false;
39
37
  const entryPoints = [];
40
- // Find all CallExpressions that look like import("path")
41
38
  scriptFile
42
39
  .getDescendantsOfKind(SyntaxKind.CallExpression)
43
40
  .forEach((callExpr) => {
44
41
  const expr = callExpr.getExpression();
45
- // Check for both "import()" and "await import()" patterns
46
42
  const isImport = expr.getText() === "import";
47
- // Check for await import pattern
48
43
  const isAwaitImport = expr.getKind() === SyntaxKind.PropertyAccessExpression &&
49
44
  expr.getText().endsWith(".import");
50
45
  if (isImport || isAwaitImport) {
@@ -54,7 +49,7 @@ function transformScriptImports(scriptContent, manifest) {
54
49
  if (importPath.startsWith("/")) {
55
50
  log("Found dynamic import with root-relative path: %s", importPath);
56
51
  entryPoints.push(importPath);
57
- const path = importPath.slice(1); // Remove leading slash
52
+ const path = importPath.slice(1);
58
53
  if (manifest[path]) {
59
54
  const transformedSrc = `/${manifest[path].file}`;
60
55
  args[0].setLiteralValue(transformedSrc);
@@ -65,19 +60,15 @@ function transformScriptImports(scriptContent, manifest) {
65
60
  }
66
61
  });
67
62
  if (hasChanges) {
68
- // Extract the transformed content from inside the wrapper function
69
63
  const fullText = scriptFile.getFullText();
70
- // Find content between the first { and the last }
71
64
  const startPos = fullText.indexOf("{") + 1;
72
65
  const endPos = fullText.lastIndexOf("}");
73
66
  const transformedContent = fullText.substring(startPos, endPos);
74
67
  return { content: transformedContent, hasChanges: true, entryPoints };
75
68
  }
76
- // Return the original content when no changes are made
77
69
  return { content: scriptContent, hasChanges: false, entryPoints };
78
70
  }
79
71
  catch (error) {
80
- // If parsing fails, fall back to the original content
81
72
  console.warn("Failed to parse inline script content:", error);
82
73
  return { content: undefined, hasChanges: false, entryPoints: [] };
83
74
  }
@@ -93,15 +84,12 @@ export async function transformJsxScriptTagsCode(code, manifest = {}) {
93
84
  const modifications = [];
94
85
  const needsRequestInfoImportRef = { value: false };
95
86
  const entryPointsPerCallExpr = new Map();
96
- // Check for existing imports up front
97
87
  let hasRequestInfoImport = false;
98
88
  let sdkWorkerImportDecl;
99
- // Scan for imports only once
100
89
  sourceFile.getImportDeclarations().forEach((importDecl) => {
101
90
  const moduleSpecifier = importDecl.getModuleSpecifierValue();
102
91
  if (moduleSpecifier === "rwsdk/worker") {
103
92
  sdkWorkerImportDecl = importDecl;
104
- // Check if requestInfo is already imported
105
93
  if (importDecl
106
94
  .getNamedImports()
107
95
  .some((namedImport) => namedImport.getName() === "requestInfo")) {
@@ -109,65 +97,52 @@ export async function transformJsxScriptTagsCode(code, manifest = {}) {
109
97
  }
110
98
  }
111
99
  });
112
- // Look for jsx function calls (jsx, jsxs, jsxDEV)
113
100
  sourceFile
114
101
  .getDescendantsOfKind(SyntaxKind.CallExpression)
115
102
  .forEach((callExpr) => {
116
103
  const expression = callExpr.getExpression();
117
104
  const expressionText = expression.getText();
118
- // Only process jsx/jsxs/jsxDEV calls
119
105
  if (expressionText !== "jsx" &&
120
106
  expressionText !== "jsxs" &&
121
107
  expressionText !== "jsxDEV") {
122
108
  return;
123
109
  }
124
- // Get arguments of the jsx call
125
110
  const args = callExpr.getArguments();
126
111
  if (args.length < 2)
127
112
  return;
128
- // First argument should be the element type
129
113
  const elementType = args[0];
130
114
  if (!Node.isStringLiteral(elementType))
131
115
  return;
132
116
  const tagName = elementType.getLiteralValue();
133
117
  const entryPoints = [];
134
- // Process script and link tags
135
118
  if (tagName === "script" || tagName === "link") {
136
- // Second argument should be the props object
137
119
  const propsArg = args[1];
138
- // Handle object literals with properties
139
120
  if (Node.isObjectLiteralExpression(propsArg)) {
140
121
  const properties = propsArg.getProperties();
141
- // Variables to track script attributes
142
122
  let hasDangerouslySetInnerHTML = false;
143
123
  let hasNonce = false;
144
124
  let hasStringLiteralChildren = false;
145
125
  let hasSrc = false;
146
- // Variables to track link attributes
147
126
  let isPreload = false;
148
127
  let hrefValue = null;
149
128
  for (const prop of properties) {
150
129
  if (Node.isPropertyAssignment(prop)) {
151
130
  const propName = prop.getName();
152
131
  const initializer = prop.getInitializer();
153
- // Check for existing nonce
154
132
  if (propName === "nonce") {
155
133
  hasNonce = true;
156
134
  }
157
- // Check for dangerouslySetInnerHTML
158
135
  if (propName === "dangerouslySetInnerHTML") {
159
136
  hasDangerouslySetInnerHTML = true;
160
137
  }
161
- // Check for src attribute
162
138
  if (tagName === "script" && propName === "src") {
163
139
  hasSrc = true;
164
- // Also process src for manifest transformation if needed
165
140
  if (Node.isStringLiteral(initializer) ||
166
141
  Node.isNoSubstitutionTemplateLiteral(initializer)) {
167
142
  const srcValue = initializer.getLiteralValue();
168
143
  if (srcValue.startsWith("/")) {
169
144
  entryPoints.push(srcValue);
170
- const path = srcValue.slice(1); // Remove leading slash
145
+ const path = srcValue.slice(1);
171
146
  if (manifest[path]) {
172
147
  const transformedSrc = `/${manifest[path].file}`;
173
148
  modifications.push({
@@ -179,18 +154,15 @@ export async function transformJsxScriptTagsCode(code, manifest = {}) {
179
154
  }
180
155
  }
181
156
  }
182
- // Check for string literal children
183
157
  if (tagName === "script" &&
184
158
  propName === "children" &&
185
159
  (Node.isStringLiteral(initializer) ||
186
160
  Node.isNoSubstitutionTemplateLiteral(initializer))) {
187
161
  hasStringLiteralChildren = true;
188
162
  const scriptContent = initializer.getLiteralValue();
189
- // Transform import statements in script content using ts-morph
190
163
  const { content: transformedContent, hasChanges: contentHasChanges, entryPoints: dynamicEntryPoints, } = transformScriptImports(scriptContent, manifest);
191
164
  entryPoints.push(...dynamicEntryPoints);
192
165
  if (contentHasChanges && transformedContent) {
193
- // Get the raw text with quotes to determine the exact format
194
166
  const isTemplateLiteral = Node.isNoSubstitutionTemplateLiteral(initializer);
195
167
  const replacementText = isTemplateLiteral
196
168
  ? "`" + transformedContent + "`"
@@ -202,7 +174,6 @@ export async function transformJsxScriptTagsCode(code, manifest = {}) {
202
174
  });
203
175
  }
204
176
  }
205
- // For link tags, first check if it's a preload/modulepreload
206
177
  if (tagName === "link") {
207
178
  if (propName === "rel" &&
208
179
  (Node.isStringLiteral(initializer) ||
@@ -220,12 +191,10 @@ export async function transformJsxScriptTagsCode(code, manifest = {}) {
220
191
  }
221
192
  }
222
193
  }
223
- // Add nonce to script tags if needed
224
194
  if (tagName === "script" &&
225
195
  !hasNonce &&
226
196
  !hasDangerouslySetInnerHTML &&
227
197
  (hasStringLiteralChildren || hasSrc)) {
228
- // Collect nonce property addition
229
198
  modifications.push({
230
199
  type: "addProperty",
231
200
  node: propsArg,
@@ -236,13 +205,12 @@ export async function transformJsxScriptTagsCode(code, manifest = {}) {
236
205
  needsRequestInfoImportRef.value = true;
237
206
  }
238
207
  }
239
- // Transform href if this is a preload link
240
208
  if (tagName === "link" &&
241
209
  isPreload &&
242
210
  hrefValue &&
243
211
  hrefValue.startsWith("/") &&
244
212
  manifest[hrefValue.slice(1)]) {
245
- const path = hrefValue.slice(1); // Remove leading slash
213
+ const path = hrefValue.slice(1);
246
214
  for (const prop of properties) {
247
215
  if (Node.isPropertyAssignment(prop) &&
248
216
  prop.getName() === "href") {
@@ -255,7 +223,6 @@ export async function transformJsxScriptTagsCode(code, manifest = {}) {
255
223
  const quote = isTemplateLiteral
256
224
  ? "`"
257
225
  : originalText.charAt(0);
258
- // Preserve the original quote style and prepare replacement text
259
226
  let replacementText;
260
227
  if (isTemplateLiteral) {
261
228
  replacementText = `\`/${transformedHref}\``;
@@ -284,23 +251,18 @@ export async function transformJsxScriptTagsCode(code, manifest = {}) {
284
251
  .join(",\n");
285
252
  const leadingCommentRanges = callExpr.getLeadingCommentRanges();
286
253
  const pureComment = leadingCommentRanges.find((r) => r.getText().includes("@__PURE__"));
287
- // Store position and static data for later processing
288
254
  const wrapInfo = {
289
255
  callExpr: callExpr,
290
256
  sideEffects: sideEffects,
291
257
  pureCommentText: pureComment?.getText(),
292
258
  };
293
- // We'll collect the actual wrap modifications after simple modifications are applied
294
259
  if (!entryPointsPerCallExpr.has(callExpr)) {
295
260
  entryPointsPerCallExpr.set(callExpr, wrapInfo);
296
261
  }
297
262
  needsRequestInfoImportRef.value = true;
298
263
  }
299
264
  });
300
- // Apply all collected modifications
301
265
  if (modifications.length > 0 || entryPointsPerCallExpr.size > 0) {
302
- // Apply modifications in the right order to avoid invalidating nodes
303
- // Apply simple modifications first (these are less likely to invalidate other nodes)
304
266
  for (const mod of modifications) {
305
267
  if (mod.type === "literalValue") {
306
268
  mod.node.setLiteralValue(mod.value);
@@ -315,15 +277,12 @@ export async function transformJsxScriptTagsCode(code, manifest = {}) {
315
277
  });
316
278
  }
317
279
  }
318
- // Apply CallExpr wrapping last (these can invalidate other nodes)
319
- // Now collect the wrap modifications with fresh data after simple modifications
320
280
  const wrapModifications = [];
321
281
  for (const [callExpr, wrapInfo] of entryPointsPerCallExpr) {
322
282
  const fullStart = callExpr.getFullStart();
323
283
  const end = callExpr.getEnd();
324
284
  const callExprText = callExpr.getText();
325
285
  const fullText = callExpr.getFullText();
326
- // Extract leading whitespace/newlines before the call expression
327
286
  const leadingWhitespace = fullText.substring(0, fullText.length - callExprText.length);
328
287
  let pureCommentText;
329
288
  let leadingTriviaText;
@@ -342,7 +301,6 @@ export async function transformJsxScriptTagsCode(code, manifest = {}) {
342
301
  leadingWhitespace: leadingWhitespace,
343
302
  });
344
303
  }
345
- // Sort by position in reverse order to avoid invalidating later nodes
346
304
  wrapModifications.sort((a, b) => b.fullStart - a.fullStart);
347
305
  for (const mod of wrapModifications) {
348
306
  if (mod.pureCommentText && mod.leadingTriviaText) {
@@ -351,13 +309,9 @@ ${mod.sideEffects},
351
309
  ${mod.pureCommentText} ${mod.callExprText}
352
310
  )`;
353
311
  const newLeadingTriviaText = mod.leadingTriviaText.replace(mod.pureCommentText, "");
354
- // By replacing from `getFullStart`, we remove the original node and all its leading trivia
355
- // and replace it with our manually reconstructed string.
356
- // This should correctly move the pure comment and preserve other comments and whitespace.
357
312
  sourceFile.replaceText([mod.fullStart, mod.end], newLeadingTriviaText + newText);
358
313
  }
359
314
  else {
360
- // Extract just the newlines and basic indentation, ignore extra padding
361
315
  const leadingNewlines = mod.leadingWhitespace.match(/\n\s*/)?.[0] || "";
362
316
  sourceFile.replaceText([mod.fullStart, mod.end], `${leadingNewlines}(
363
317
  ${mod.sideEffects},
@@ -365,16 +319,13 @@ ${mod.callExprText}
365
319
  )`);
366
320
  }
367
321
  }
368
- // Add requestInfo import if needed and not already imported
369
322
  if (needsRequestInfoImportRef.value) {
370
323
  if (sdkWorkerImportDecl) {
371
- // Module is imported but need to add requestInfo
372
324
  if (!hasRequestInfoImport) {
373
325
  sdkWorkerImportDecl.addNamedImport("requestInfo");
374
326
  }
375
327
  }
376
328
  else {
377
- // Add new import declaration
378
329
  sourceFile.addImportDeclaration({
379
330
  moduleSpecifier: "rwsdk/worker",
380
331
  namedImports: ["requestInfo"],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rwsdk",
3
- "version": "0.2.0-alpha.16-test.20250825032050",
3
+ "version": "0.2.0-alpha.18",
4
4
  "description": "Build fast, server-driven webapps on Cloudflare with SSR, RSC, and realtime",
5
5
  "type": "module",
6
6
  "bin": {