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

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.
@@ -7,9 +7,6 @@ import chokidar from "chokidar";
7
7
  import { lock } from "proper-lockfile";
8
8
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
9
  const getPackageManagerInfo = (targetDir) => {
10
- if (existsSync(path.join(targetDir, "bun.lock"))) {
11
- return { name: "bun", lockFile: "bun.lock", command: "add" };
12
- }
13
10
  const pnpmResult = {
14
11
  name: "pnpm",
15
12
  lockFile: "pnpm-lock.yaml",
@@ -66,23 +63,6 @@ const performFullSync = async (sdkDir, targetDir) => {
66
63
  // Clean up vite cache
67
64
  await cleanupViteEntries(targetDir);
68
65
  try {
69
- try {
70
- originalSdkPackageJson = await fs.readFile(sdkPackageJsonPath, "utf-8");
71
- const packageJson = JSON.parse(originalSdkPackageJson);
72
- const originalVersion = packageJson.version;
73
- const timestamp = new Date()
74
- .toISOString()
75
- .replace(/[-:T.]/g, "")
76
- .slice(0, 14);
77
- const newVersion = `${originalVersion}+build.${timestamp}`;
78
- console.log(`Temporarily setting version to ${newVersion}`);
79
- packageJson.version = newVersion;
80
- await fs.writeFile(sdkPackageJsonPath, JSON.stringify(packageJson, null, 2));
81
- }
82
- catch (e) {
83
- console.warn("Could not modify package.json version, proceeding without it.");
84
- originalSdkPackageJson = null; // don't restore if we failed to modify
85
- }
86
66
  console.log("📦 Packing SDK...");
87
67
  const packResult = await $({ cwd: sdkDir }) `npm pack --json`;
88
68
  const json = JSON.parse(packResult.stdout || "[]");
@@ -104,29 +84,6 @@ const performFullSync = async (sdkDir, targetDir) => {
104
84
  .readFile(lockfilePath, "utf-8")
105
85
  .catch(() => null);
106
86
  try {
107
- // For bun, we need to remove the existing dependency from package.json
108
- // before adding the tarball to avoid a dependency loop error.
109
- if (pm.name === "bun" && originalPackageJson) {
110
- try {
111
- const targetPackageJson = JSON.parse(originalPackageJson);
112
- let modified = false;
113
- if (targetPackageJson.dependencies?.rwsdk) {
114
- delete targetPackageJson.dependencies.rwsdk;
115
- modified = true;
116
- }
117
- if (targetPackageJson.devDependencies?.rwsdk) {
118
- delete targetPackageJson.devDependencies.rwsdk;
119
- modified = true;
120
- }
121
- if (modified) {
122
- console.log("Temporarily removing rwsdk from target package.json to prevent dependency loop with bun.");
123
- await fs.writeFile(packageJsonPath, JSON.stringify(targetPackageJson, null, 2));
124
- }
125
- }
126
- catch (e) {
127
- console.warn("Could not modify target package.json, proceeding anyway.");
128
- }
129
- }
130
87
  const cmd = pm.name;
131
88
  const args = [pm.command];
132
89
  if (pm.name === "yarn") {
@@ -1,4 +1,4 @@
1
- import { Project, Node, SyntaxKind, } from "ts-morph";
1
+ import { Project, Node, SyntaxKind } from "ts-morph";
2
2
  import { readFile } from "node:fs/promises";
3
3
  import { pathExists } from "fs-extra";
4
4
  import debug from "debug";
@@ -90,9 +90,8 @@ export async function transformJsxScriptTagsCode(code, manifest = {}) {
90
90
  }
91
91
  const project = new Project({ useInMemoryFileSystem: true });
92
92
  const sourceFile = project.createSourceFile("temp.tsx", code);
93
- const modifications = [];
93
+ let hasModifications = false;
94
94
  const needsRequestInfoImportRef = { value: false };
95
- const entryPointsPerCallExpr = new Map();
96
95
  // Check for existing imports up front
97
96
  let hasRequestInfoImport = false;
98
97
  let sdkWorkerImportDecl;
@@ -170,11 +169,8 @@ export async function transformJsxScriptTagsCode(code, manifest = {}) {
170
169
  const path = srcValue.slice(1); // Remove leading slash
171
170
  if (manifest[path]) {
172
171
  const transformedSrc = `/${manifest[path].file}`;
173
- modifications.push({
174
- type: "literalValue",
175
- node: initializer,
176
- value: transformedSrc,
177
- });
172
+ initializer.setLiteralValue(transformedSrc);
173
+ hasModifications = true;
178
174
  }
179
175
  }
180
176
  }
@@ -192,14 +188,14 @@ export async function transformJsxScriptTagsCode(code, manifest = {}) {
192
188
  if (contentHasChanges && transformedContent) {
193
189
  // Get the raw text with quotes to determine the exact format
194
190
  const isTemplateLiteral = Node.isNoSubstitutionTemplateLiteral(initializer);
195
- const replacementText = isTemplateLiteral
196
- ? "`" + transformedContent + "`"
197
- : JSON.stringify(transformedContent);
198
- modifications.push({
199
- type: "replaceText",
200
- node: initializer,
201
- text: replacementText,
202
- });
191
+ if (isTemplateLiteral) {
192
+ // Simply wrap the transformed content in backticks
193
+ initializer.replaceWithText("`" + transformedContent + "`");
194
+ }
195
+ else {
196
+ initializer.replaceWithText(JSON.stringify(transformedContent));
197
+ }
198
+ hasModifications = true;
203
199
  }
204
200
  }
205
201
  // For link tags, first check if it's a preload/modulepreload
@@ -225,16 +221,15 @@ export async function transformJsxScriptTagsCode(code, manifest = {}) {
225
221
  !hasNonce &&
226
222
  !hasDangerouslySetInnerHTML &&
227
223
  (hasStringLiteralChildren || hasSrc)) {
228
- // Collect nonce property addition
229
- modifications.push({
230
- type: "addProperty",
231
- node: propsArg,
224
+ // Add nonce property to the props object
225
+ propsArg.addPropertyAssignment({
232
226
  name: "nonce",
233
227
  initializer: "requestInfo.rw.nonce",
234
228
  });
235
229
  if (!hasRequestInfoImport) {
236
230
  needsRequestInfoImportRef.value = true;
237
231
  }
232
+ hasModifications = true;
238
233
  }
239
234
  // Transform href if this is a preload link
240
235
  if (tagName === "link" &&
@@ -255,22 +250,17 @@ export async function transformJsxScriptTagsCode(code, manifest = {}) {
255
250
  const quote = isTemplateLiteral
256
251
  ? "`"
257
252
  : originalText.charAt(0);
258
- // Preserve the original quote style and prepare replacement text
259
- let replacementText;
253
+ // Preserve the original quote style
260
254
  if (isTemplateLiteral) {
261
- replacementText = `\`/${transformedHref}\``;
255
+ initializer.replaceWithText(`\`/${transformedHref}\``);
262
256
  }
263
257
  else if (quote === '"') {
264
- replacementText = `"/${transformedHref}"`;
258
+ initializer.replaceWithText(`"/${transformedHref}"`);
265
259
  }
266
260
  else {
267
- replacementText = `'/${transformedHref}'`;
261
+ initializer.replaceWithText(`'/${transformedHref}'`);
268
262
  }
269
- modifications.push({
270
- type: "replaceText",
271
- node: initializer,
272
- text: replacementText,
273
- });
263
+ hasModifications = true;
274
264
  }
275
265
  }
276
266
  }
@@ -284,103 +274,51 @@ export async function transformJsxScriptTagsCode(code, manifest = {}) {
284
274
  .join(",\n");
285
275
  const leadingCommentRanges = callExpr.getLeadingCommentRanges();
286
276
  const pureComment = leadingCommentRanges.find((r) => r.getText().includes("@__PURE__"));
287
- // Store position and static data for later processing
288
- const wrapInfo = {
289
- callExpr: callExpr,
290
- sideEffects: sideEffects,
291
- pureCommentText: pureComment?.getText(),
292
- };
293
- // We'll collect the actual wrap modifications after simple modifications are applied
294
- if (!entryPointsPerCallExpr.has(callExpr)) {
295
- entryPointsPerCallExpr.set(callExpr, wrapInfo);
296
- }
297
- needsRequestInfoImportRef.value = true;
298
- }
299
- });
300
- // Apply all collected modifications
301
- 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
- for (const mod of modifications) {
305
- if (mod.type === "literalValue") {
306
- mod.node.setLiteralValue(mod.value);
307
- }
308
- else if (mod.type === "replaceText") {
309
- mod.node.replaceWithText(mod.text);
310
- }
311
- else if (mod.type === "addProperty") {
312
- mod.node.addPropertyAssignment({
313
- name: mod.name,
314
- initializer: mod.initializer,
315
- });
316
- }
317
- }
318
- // Apply CallExpr wrapping last (these can invalidate other nodes)
319
- // Now collect the wrap modifications with fresh data after simple modifications
320
- const wrapModifications = [];
321
- for (const [callExpr, wrapInfo] of entryPointsPerCallExpr) {
322
- const fullStart = callExpr.getFullStart();
323
- const end = callExpr.getEnd();
324
277
  const callExprText = callExpr.getText();
325
- const fullText = callExpr.getFullText();
326
- // Extract leading whitespace/newlines before the call expression
327
- const leadingWhitespace = fullText.substring(0, fullText.length - callExprText.length);
328
- let pureCommentText;
329
- let leadingTriviaText;
330
- if (wrapInfo.pureCommentText) {
331
- pureCommentText = wrapInfo.pureCommentText;
332
- leadingTriviaText = leadingWhitespace;
333
- }
334
- wrapModifications.push({
335
- type: "wrapCallExpr",
336
- sideEffects: wrapInfo.sideEffects,
337
- pureCommentText: pureCommentText,
338
- leadingTriviaText: leadingTriviaText,
339
- fullStart: fullStart,
340
- end: end,
341
- callExprText: callExprText,
342
- leadingWhitespace: leadingWhitespace,
343
- });
344
- }
345
- // Sort by position in reverse order to avoid invalidating later nodes
346
- wrapModifications.sort((a, b) => b.fullStart - a.fullStart);
347
- for (const mod of wrapModifications) {
348
- if (mod.pureCommentText && mod.leadingTriviaText) {
278
+ if (pureComment) {
279
+ const pureCommentText = pureComment.getText();
349
280
  const newText = `(
350
- ${mod.sideEffects},
351
- ${mod.pureCommentText} ${mod.callExprText}
352
- )`;
353
- const newLeadingTriviaText = mod.leadingTriviaText.replace(mod.pureCommentText, "");
281
+ ${sideEffects},
282
+ ${pureCommentText} ${callExprText}
283
+ )`;
284
+ const fullText = callExpr.getFullText();
285
+ const leadingTriviaText = fullText.substring(0, fullText.length - callExprText.length);
286
+ const newLeadingTriviaText = leadingTriviaText.replace(pureCommentText, "");
354
287
  // By replacing from `getFullStart`, we remove the original node and all its leading trivia
355
288
  // and replace it with our manually reconstructed string.
356
289
  // This should correctly move the pure comment and preserve other comments and whitespace.
357
- sourceFile.replaceText([mod.fullStart, mod.end], newLeadingTriviaText + newText);
290
+ callExpr
291
+ .getSourceFile()
292
+ .replaceText([callExpr.getFullStart(), callExpr.getEnd()], newLeadingTriviaText + newText);
358
293
  }
359
294
  else {
360
- // Extract just the newlines and basic indentation, ignore extra padding
361
- const leadingNewlines = mod.leadingWhitespace.match(/\n\s*/)?.[0] || "";
362
- sourceFile.replaceText([mod.fullStart, mod.end], `${leadingNewlines}(
363
- ${mod.sideEffects},
364
- ${mod.callExprText}
365
- )`);
295
+ callExpr.replaceWithText(`(
296
+ ${sideEffects},
297
+ ${callExprText}
298
+ )`);
366
299
  }
300
+ needsRequestInfoImportRef.value = true;
301
+ hasModifications = true;
367
302
  }
368
- // Add requestInfo import if needed and not already imported
369
- if (needsRequestInfoImportRef.value) {
370
- if (sdkWorkerImportDecl) {
371
- // Module is imported but need to add requestInfo
372
- if (!hasRequestInfoImport) {
373
- sdkWorkerImportDecl.addNamedImport("requestInfo");
374
- }
375
- }
376
- else {
377
- // Add new import declaration
378
- sourceFile.addImportDeclaration({
379
- moduleSpecifier: "rwsdk/worker",
380
- namedImports: ["requestInfo"],
381
- });
303
+ });
304
+ // Add requestInfo import if needed and not already imported
305
+ if (needsRequestInfoImportRef.value && hasModifications) {
306
+ if (sdkWorkerImportDecl) {
307
+ // Module is imported but need to add requestInfo
308
+ if (!hasRequestInfoImport) {
309
+ sdkWorkerImportDecl.addNamedImport("requestInfo");
382
310
  }
383
311
  }
312
+ else {
313
+ // Add new import declaration
314
+ sourceFile.addImportDeclaration({
315
+ moduleSpecifier: "rwsdk/worker",
316
+ namedImports: ["requestInfo"],
317
+ });
318
+ }
319
+ }
320
+ // Return the transformed code only if modifications were made
321
+ if (hasModifications) {
384
322
  return {
385
323
  code: sourceFile.getFullText(),
386
324
  map: null,
@@ -400,8 +338,6 @@ export const transformJsxScriptTagsPlugin = ({ manifestPath, }) => {
400
338
  id.endsWith(".tsx") &&
401
339
  !id.includes("node_modules") &&
402
340
  hasJsxFunctions(code)) {
403
- log("Transforming JSX script tags in %s", id);
404
- process.env.VERBOSE && log("Code:\n%s", code);
405
341
  const manifest = isBuild ? await readManifest(manifestPath) : {};
406
342
  const result = await transformJsxScriptTagsCode(code, manifest);
407
343
  if (result) {
@@ -1,10 +1,5 @@
1
1
  import { describe, it, expect } from "vitest";
2
2
  import { transformJsxScriptTagsCode } from "./transformJsxScriptTagsPlugin.mjs";
3
- import jsBeautify from "js-beautify";
4
- // Helper function to normalize code formatting for test comparisons
5
- function normalizeCode(code) {
6
- return jsBeautify(code, { indent_size: 2 });
7
- }
8
3
  describe("transformJsxScriptTagsCode", () => {
9
4
  const mockManifest = {
10
5
  "src/client.tsx": { file: "assets/client-a1b2c3d4.js" },
@@ -19,17 +14,17 @@ describe("transformJsxScriptTagsCode", () => {
19
14
  })
20
15
  `;
21
16
  const result = await transformJsxScriptTagsCode(code, mockManifest);
22
- const expected = `import { requestInfo } from "rwsdk/worker";
17
+ expect(result?.code).toEqual(`import { requestInfo } from "rwsdk/worker";
23
18
 
24
- (
25
- (requestInfo.rw.scriptsToBeLoaded.add("/src/client.tsx")),
26
- jsx("script", {
27
- src: "/assets/client-a1b2c3d4.js",
28
- type: "module",
29
- nonce: requestInfo.rw.nonce
30
- })
31
- )`;
32
- expect(normalizeCode(result?.code || "")).toEqual(normalizeCode(expected));
19
+ (
20
+ (requestInfo.rw.scriptsToBeLoaded.add("/src/client.tsx")),
21
+ jsx("script", {
22
+ src: "/assets/client-a1b2c3d4.js",
23
+ type: "module",
24
+ nonce: requestInfo.rw.nonce
25
+ })
26
+ )
27
+ `);
33
28
  });
34
29
  it("transforms inline scripts with dynamic imports", async () => {
35
30
  const code = `
@@ -39,32 +34,32 @@ nonce: requestInfo.rw.nonce
39
34
  })
40
35
  `;
41
36
  const result = await transformJsxScriptTagsCode(code, mockManifest);
42
- const expected = `import { requestInfo } from "rwsdk/worker";
37
+ expect(result?.code).toEqual(`import { requestInfo } from "rwsdk/worker";
43
38
 
44
- (
45
- (requestInfo.rw.scriptsToBeLoaded.add("/src/client.tsx")),
46
- jsx("script", {
47
- type: "module",
48
- children: "import('/assets/client-a1b2c3d4.js').then(module => { console.log(module); })",
49
- nonce: requestInfo.rw.nonce
50
- })
51
- )`;
52
- expect(normalizeCode(result?.code || "")).toEqual(normalizeCode(expected));
39
+ (
40
+ (requestInfo.rw.scriptsToBeLoaded.add("/src/client.tsx")),
41
+ jsx("script", {
42
+ type: "module",
43
+ children: "import('/assets/client-a1b2c3d4.js').then(module => { console.log(module); })",
44
+ nonce: requestInfo.rw.nonce
45
+ })
46
+ )
47
+ `);
53
48
  });
54
49
  it("transforms inline scripts with type=module", async () => {
55
50
  const code = `
56
51
  jsx("script", { type: "module", children: "import('/src/client.tsx')" })
57
52
  `;
58
53
  const result = await transformJsxScriptTagsCode(code, mockManifest);
59
- const expected = `import { requestInfo } from "rwsdk/worker";
54
+ expect(result?.code).toEqual(`import { requestInfo } from "rwsdk/worker";
60
55
 
61
- (
62
- (requestInfo.rw.scriptsToBeLoaded.add("/src/client.tsx")),
63
- jsx("script", { type: "module", children: "import('/assets/client-a1b2c3d4.js')",
64
- nonce: requestInfo.rw.nonce
65
- })
66
- )`;
67
- expect(normalizeCode(result?.code || "")).toEqual(normalizeCode(expected));
56
+ (
57
+ (requestInfo.rw.scriptsToBeLoaded.add("/src/client.tsx")),
58
+ jsx("script", { type: "module", children: "import('/assets/client-a1b2c3d4.js')",
59
+ nonce: requestInfo.rw.nonce
60
+ })
61
+ )
62
+ `);
68
63
  });
69
64
  it("transforms inline scripts with multiline content", async () => {
70
65
  const code = `
@@ -81,13 +76,13 @@ nonce: requestInfo.rw.nonce
81
76
  })
82
77
  `;
83
78
  const result = await transformJsxScriptTagsCode(code, mockManifest);
84
- const expected = `import { requestInfo } from "rwsdk/worker";
79
+ expect(result?.code).toEqual(`import { requestInfo } from "rwsdk/worker";
85
80
 
86
- (
87
- (requestInfo.rw.scriptsToBeLoaded.add("/src/entry.js")),
88
- jsx("script", {
89
- type: "module",
90
- children: \`
81
+ (
82
+ (requestInfo.rw.scriptsToBeLoaded.add("/src/entry.js")),
83
+ jsx("script", {
84
+ type: "module",
85
+ children: \`
91
86
  // Some comments here
92
87
  const init = async () => {
93
88
  await import('/assets/entry-e5f6g7h8.js');
@@ -95,37 +90,37 @@ children: \`
95
90
  };
96
91
  init();
97
92
  \`,
98
- nonce: requestInfo.rw.nonce
99
- })
100
- )`;
101
- expect(normalizeCode(result?.code || "")).toEqual(normalizeCode(expected));
93
+ nonce: requestInfo.rw.nonce
94
+ })
95
+ )
96
+ `);
102
97
  });
103
98
  it("transforms multiple imports in the same inline script", async () => {
104
99
  const code = `
105
100
  jsx("script", {
106
101
  type: "module",
107
102
  children: \`
108
- import('/src/client.tsx');
109
- import('/src/entry.js');
110
- \`
103
+ import('/src/client.tsx');
104
+ import('/src/entry.js');
105
+ \`
111
106
  })
112
107
  `;
113
108
  const result = await transformJsxScriptTagsCode(code, mockManifest);
114
- const expected = `import { requestInfo } from "rwsdk/worker";
109
+ expect(result?.code).toEqual(`import { requestInfo } from "rwsdk/worker";
115
110
 
116
- (
117
- (requestInfo.rw.scriptsToBeLoaded.add("/src/client.tsx")),
111
+ (
112
+ (requestInfo.rw.scriptsToBeLoaded.add("/src/client.tsx")),
118
113
  (requestInfo.rw.scriptsToBeLoaded.add("/src/entry.js")),
119
- jsx("script", {
120
- type: "module",
121
- children: \`
122
- import('/assets/client-a1b2c3d4.js');
123
- import('/assets/entry-e5f6g7h8.js');
124
- \`,
125
- nonce: requestInfo.rw.nonce
126
- })
127
- )`;
128
- expect(normalizeCode(result?.code || "")).toEqual(normalizeCode(expected));
114
+ jsx("script", {
115
+ type: "module",
116
+ children: \`
117
+ import('/assets/client-a1b2c3d4.js');
118
+ import('/assets/entry-e5f6g7h8.js');
119
+ \`,
120
+ nonce: requestInfo.rw.nonce
121
+ })
122
+ )
123
+ `);
129
124
  });
130
125
  it("transforms link href attributes with preload rel", async () => {
131
126
  const code = `
@@ -182,33 +177,33 @@ nonce: requestInfo.rw.nonce
182
177
  })
183
178
  `;
184
179
  const result = await transformJsxScriptTagsCode(code, mockManifest);
185
- const expected = `import { requestInfo } from "rwsdk/worker";
180
+ expect(result?.code).toEqual(`import { requestInfo } from "rwsdk/worker";
186
181
 
187
- jsx("html", {
188
- lang: "en",
189
- children: [
190
- jsx("head", {
191
- children: [
192
- jsx("meta", { charSet: "utf-8" }),
193
- jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
194
- jsx("title", { children: "@redwoodjs/starter-standard" }),
195
- jsx("link", { rel: "modulepreload", href: "/assets/client-a1b2c3d4.js", as: "script" })
196
- ]
197
- }),
198
- jsx("body", {
199
- children: [
200
- jsx("div", { id: "root", children: props.children }),
201
- (
202
- (requestInfo.rw.scriptsToBeLoaded.add("/src/client.tsx")),
203
- jsx("script", { children: "import(\\"/assets/client-a1b2c3d4.js\\")",
204
- nonce: requestInfo.rw.nonce
205
- })
206
- )
207
- ]
208
- })
209
- ]
210
- })`;
211
- expect(normalizeCode(result?.code || "")).toEqual(normalizeCode(expected));
182
+ jsx("html", {
183
+ lang: "en",
184
+ children: [
185
+ jsx("head", {
186
+ children: [
187
+ jsx("meta", { charSet: "utf-8" }),
188
+ jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
189
+ jsx("title", { children: "@redwoodjs/starter-standard" }),
190
+ jsx("link", { rel: "modulepreload", href: "/assets/client-a1b2c3d4.js", as: "script" })
191
+ ]
192
+ }),
193
+ jsx("body", {
194
+ children: [
195
+ jsx("div", { id: "root", children: props.children }),
196
+ (
197
+ (requestInfo.rw.scriptsToBeLoaded.add("/src/client.tsx")),
198
+ jsx("script", { children: "import(\\"\/assets\/client-a1b2c3d4.js\\")",
199
+ nonce: requestInfo.rw.nonce
200
+ })
201
+ )
202
+ ]
203
+ })
204
+ ]
205
+ })
206
+ `);
212
207
  });
213
208
  it("returns null when no transformations are needed", async () => {
214
209
  const code = `
@@ -225,17 +220,17 @@ nonce: requestInfo.rw.nonce
225
220
  })
226
221
  `;
227
222
  const result = await transformJsxScriptTagsCode(code, mockManifest);
228
- const expected = `import { requestInfo } from "rwsdk/worker";
223
+ expect(result?.code).toEqual(`import { requestInfo } from "rwsdk/worker";
229
224
 
230
- (
231
- (requestInfo.rw.scriptsToBeLoaded.add("/src/non-existent.js")),
232
- jsx("script", {
233
- src: "/src/non-existent.js",
234
- type: "module",
235
- nonce: requestInfo.rw.nonce
236
- })
237
- )`;
238
- expect(normalizeCode(result?.code || "")).toEqual(normalizeCode(expected));
225
+ (
226
+ (requestInfo.rw.scriptsToBeLoaded.add("/src/non-existent.js")),
227
+ jsx("script", {
228
+ src: "/src/non-existent.js",
229
+ type: "module",
230
+ nonce: requestInfo.rw.nonce
231
+ })
232
+ )
233
+ `);
239
234
  });
240
235
  it("adds nonce to script tags with src attribute and imports requestInfo", async () => {
241
236
  const code = `
@@ -245,17 +240,17 @@ nonce: requestInfo.rw.nonce
245
240
  })
246
241
  `;
247
242
  const result = await transformJsxScriptTagsCode(code, mockManifest);
248
- const expected = `import { requestInfo } from "rwsdk/worker";
243
+ expect(result?.code).toEqual(`import { requestInfo } from "rwsdk/worker";
249
244
 
250
- (
251
- (requestInfo.rw.scriptsToBeLoaded.add("/src/client.tsx")),
252
- jsx("script", {
253
- src: "/assets/client-a1b2c3d4.js",
254
- type: "module",
255
- nonce: requestInfo.rw.nonce
256
- })
257
- )`;
258
- expect(normalizeCode(result?.code || "")).toEqual(normalizeCode(expected));
245
+ (
246
+ (requestInfo.rw.scriptsToBeLoaded.add("/src/client.tsx")),
247
+ jsx("script", {
248
+ src: "/assets/client-a1b2c3d4.js",
249
+ type: "module",
250
+ nonce: requestInfo.rw.nonce
251
+ })
252
+ )
253
+ `);
259
254
  });
260
255
  it("adds nonce to script tags with string literal children", async () => {
261
256
  const code = `
@@ -352,242 +347,16 @@ nonce: requestInfo.rw.nonce
352
347
  `;
353
348
  // Call without providing manifest (simulating dev mode)
354
349
  const result = await transformJsxScriptTagsCode(code);
355
- const expected = `import { requestInfo } from "rwsdk/worker";
356
-
357
- (
358
- (requestInfo.rw.scriptsToBeLoaded.add("/src/client.tsx")),
359
- jsx("script", {
360
- src: "/src/client.tsx",
361
- type: "module",
362
- nonce: requestInfo.rw.nonce
363
- })
364
- )`;
365
- expect(normalizeCode(result?.code || "")).toEqual(normalizeCode(expected));
366
- });
367
- it("regression favicon links", async () => {
368
- const code = `
369
- import { jsxDEV } from "react/jsx-dev-runtime";
370
- import styles from "./index.css?url";
371
- export const Document = ({
372
- children
373
- }) => /* @__PURE__ */ jsxDEV("html", { lang: "en", children: [
374
- /* @__PURE__ */ jsxDEV("head", { children: [
375
- /* @__PURE__ */ jsxDEV("meta", { charSet: "utf-8" }, void 0, false, {
376
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
377
- lineNumber: 8,
378
- columnNumber: 4
379
- }, this),
380
- /* @__PURE__ */ jsxDEV("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }, void 0, false, {
381
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
382
- lineNumber: 9,
383
- columnNumber: 4
384
- }, this),
385
- /* @__PURE__ */ jsxDEV("title", { children: "rwsdk-guestbook" }, void 0, false, {
386
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
387
- lineNumber: 10,
388
- columnNumber: 4
389
- }, this),
390
- /* @__PURE__ */ jsxDEV("link", { rel: "preconnect", href: "https://fonts.googleapis.com" }, void 0, false, {
391
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
392
- lineNumber: 11,
393
- columnNumber: 4
394
- }, this),
395
- /* @__PURE__ */ jsxDEV(
396
- "link",
397
- {
398
- rel: "preconnect",
399
- href: "https://fonts.gstatic.com",
400
- crossOrigin: "anonymous"
401
- },
402
- void 0,
403
- false,
404
- {
405
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
406
- lineNumber: 12,
407
- columnNumber: 4
408
- },
409
- this
410
- ),
411
- /* @__PURE__ */ jsxDEV(
412
- "link",
413
- {
414
- href: "https://fonts.googleapis.com/css2?family=Geist+Mono:wght@100..900&display=swap",
415
- rel: "stylesheet"
416
- },
417
- void 0,
418
- false,
419
- {
420
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
421
- lineNumber: 17,
422
- columnNumber: 4
423
- },
424
- this
425
- ),
426
- /* @__PURE__ */ jsxDEV("script", { src: "/theme-script.js" }, void 0, false, {
427
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
428
- lineNumber: 21,
429
- columnNumber: 4
430
- }, this),
431
- /* @__PURE__ */ jsxDEV("link", { rel: "icon", href: "/favicon.svg" }, void 0, false, {
432
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
433
- lineNumber: 22,
434
- columnNumber: 4
435
- }, this),
436
- /* @__PURE__ */ jsxDEV("link", { rel: "modulepreload", href: "/src/client.tsx" }, void 0, false, {
437
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
438
- lineNumber: 23,
439
- columnNumber: 4
440
- }, this),
441
- /* @__PURE__ */ jsxDEV("link", { rel: "stylesheet", href: styles }, void 0, false, {
442
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
443
- lineNumber: 24,
444
- columnNumber: 4
445
- }, this)
446
- ] }, void 0, true, {
447
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
448
- lineNumber: 7,
449
- columnNumber: 3
450
- }, this),
451
- /* @__PURE__ */ jsxDEV("body", { children: [
452
- /* @__PURE__ */ jsxDEV("div", { id: "root", children }, void 0, false, {
453
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
454
- lineNumber: 27,
455
- columnNumber: 4
456
- }, this),
457
- /* @__PURE__ */ jsxDEV("script", { children: 'import("/src/client.tsx")' }, void 0, false, {
458
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
459
- lineNumber: 28,
460
- columnNumber: 4
461
- }, this)
462
- ] }, void 0, true, {
463
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
464
- lineNumber: 26,
465
- columnNumber: 3
466
- }, this)
467
- ] }, void 0, true, {
468
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
469
- lineNumber: 6,
470
- columnNumber: 2
471
- }, this);
472
- `;
473
- const result = await transformJsxScriptTagsCode(code, mockManifest);
474
- // For this complex test, we'll just verify the key transformations
475
- const expected = `
476
- import { jsxDEV } from "react/jsx-dev-runtime";
477
- import styles from "./index.css?url";
478
- import { requestInfo } from "rwsdk/worker";
350
+ expect(result?.code).toEqual(`import { requestInfo } from "rwsdk/worker";
479
351
 
480
- export const Document = ({
481
- children
482
- }) => /* @__PURE__ */ jsxDEV("html", { lang: "en", children: [
483
- /* @__PURE__ */ jsxDEV("head", { children: [
484
- /* @__PURE__ */ jsxDEV("meta", { charSet: "utf-8" }, void 0, false, {
485
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
486
- lineNumber: 8,
487
- columnNumber: 4
488
- }, this),
489
- /* @__PURE__ */ jsxDEV("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }, void 0, false, {
490
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
491
- lineNumber: 9,
492
- columnNumber: 4
493
- }, this),
494
- /* @__PURE__ */ jsxDEV("title", { children: "rwsdk-guestbook" }, void 0, false, {
495
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
496
- lineNumber: 10,
497
- columnNumber: 4
498
- }, this),
499
- /* @__PURE__ */ jsxDEV("link", { rel: "preconnect", href: "https://fonts.googleapis.com" }, void 0, false, {
500
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
501
- lineNumber: 11,
502
- columnNumber: 4
503
- }, this),
504
- /* @__PURE__ */ jsxDEV(
505
- "link",
506
- {
507
- rel: "preconnect",
508
- href: "https://fonts.gstatic.com",
509
- crossOrigin: "anonymous"
510
- },
511
- void 0,
512
- false,
513
- {
514
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
515
- lineNumber: 12,
516
- columnNumber: 4
517
- },
518
- this
519
- ),
520
- /* @__PURE__ */ jsxDEV(
521
- "link",
522
- {
523
- href: "https://fonts.googleapis.com/css2?family=Geist+Mono:wght@100..900&display=swap",
524
- rel: "stylesheet"
525
- },
526
- void 0,
527
- false,
528
- {
529
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
530
- lineNumber: 17,
531
- columnNumber: 4
532
- },
533
- this
534
- ),
535
- (
536
- (requestInfo.rw.scriptsToBeLoaded.add("/theme-script.js")),
537
- /* @__PURE__ */ jsxDEV("script", { src: "/theme-script.js",
538
- nonce: requestInfo.rw.nonce
539
- }, void 0, false, {
540
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
541
- lineNumber: 21,
542
- columnNumber: 4
543
- }, this)
544
- ),
545
- /* @__PURE__ */ jsxDEV("link", { rel: "icon", href: "/favicon.svg" }, void 0, false, {
546
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
547
- lineNumber: 22,
548
- columnNumber: 4
549
- }, this),
550
- /* @__PURE__ */ jsxDEV("link", { rel: "modulepreload", href: "/assets/client-a1b2c3d4.js" }, void 0, false, {
551
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
552
- lineNumber: 23,
553
- columnNumber: 4
554
- }, this),
555
- /* @__PURE__ */ jsxDEV("link", { rel: "stylesheet", href: styles }, void 0, false, {
556
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
557
- lineNumber: 24,
558
- columnNumber: 4
559
- }, this)
560
- ] }, void 0, true, {
561
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
562
- lineNumber: 7,
563
- columnNumber: 3
564
- }, this),
565
- /* @__PURE__ */ jsxDEV("body", { children: [
566
- /* @__PURE__ */ jsxDEV("div", { id: "root", children }, void 0, false, {
567
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
568
- lineNumber: 27,
569
- columnNumber: 4
570
- }, this),
571
- (
572
- (requestInfo.rw.scriptsToBeLoaded.add("/src/client.tsx")),
573
- /* @__PURE__ */ jsxDEV("script", { children: "import(\\"/assets/client-a1b2c3d4.js\\")",
574
- nonce: requestInfo.rw.nonce
575
- }, void 0, false, {
576
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
577
- lineNumber: 28,
578
- columnNumber: 4
579
- }, this)
580
- )
581
- ] }, void 0, true, {
582
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
583
- lineNumber: 26,
584
- columnNumber: 3
585
- }, this)
586
- ] }, void 0, true, {
587
- fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
588
- lineNumber: 6,
589
- columnNumber: 2
590
- }, this);`;
591
- expect(normalizeCode(result?.code || "")).toEqual(normalizeCode(expected));
352
+ (
353
+ (requestInfo.rw.scriptsToBeLoaded.add("/src/client.tsx")),
354
+ jsx("script", {
355
+ src: "/src/client.tsx",
356
+ type: "module",
357
+ nonce: requestInfo.rw.nonce
358
+ })
359
+ )
360
+ `);
592
361
  });
593
362
  });
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.17",
4
4
  "description": "Build fast, server-driven webapps on Cloudflare with SSR, RSC, and realtime",
5
5
  "type": "module",
6
6
  "bin": {
@@ -154,10 +154,10 @@
154
154
  "wrangler": "^4.20.5"
155
155
  },
156
156
  "peerDependencies": {
157
+ "vite": "^6.2.6",
157
158
  "react": ">=19.2.0-0 <20",
158
159
  "react-dom": ">=19.2.0-0 <20",
159
- "react-server-dom-webpack": ">=19.2.0-0 <20",
160
- "vite": "^6.2.6"
160
+ "react-server-dom-webpack": ">=19.2.0-0 <20"
161
161
  },
162
162
  "optionalDependencies": {
163
163
  "react": "19.2.0-canary-39cad7af-20250411",
@@ -178,11 +178,9 @@
178
178
  "packageManager": "pnpm@9.14.4+sha512.c8180b3fbe4e4bca02c94234717896b5529740a6cbadf19fa78254270403ea2f27d4e1d46a08a0f56c89b63dc8ebfd3ee53326da720273794e6200fcf0d184ab",
179
179
  "devDependencies": {
180
180
  "@types/debug": "^4.1.12",
181
- "@types/js-beautify": "^1.14.3",
182
181
  "@types/lodash": "^4.17.16",
183
182
  "@types/node": "^22.14.0",
184
183
  "@types/proper-lockfile": "^4.1.4",
185
- "js-beautify": "^1.15.4",
186
184
  "semver": "^7.7.1",
187
185
  "tsx": "^4.19.4",
188
186
  "typescript": "^5.8.3",