rwsdk 0.1.16 → 0.1.17-test.20250715200658
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/lib/$.d.mts +8 -0
- package/dist/lib/$.mjs +5 -0
- package/dist/lib/constants.d.mts +4 -0
- package/dist/lib/constants.mjs +6 -0
- package/dist/lib/findWranglerConfig.d.mts +1 -0
- package/dist/lib/findWranglerConfig.mjs +12 -0
- package/dist/lib/getShortName.d.mts +1 -0
- package/dist/lib/getShortName.mjs +2 -0
- package/dist/lib/getSrcPaths.d.ts +15 -0
- package/dist/lib/getSrcPaths.js +80 -0
- package/dist/lib/hasPkgScript.d.mts +1 -0
- package/dist/lib/hasPkgScript.mjs +9 -0
- package/dist/lib/jsonUtils.d.mts +28 -0
- package/dist/lib/jsonUtils.mjs +167 -0
- package/dist/lib/setupEnvFiles.d.mts +4 -0
- package/dist/lib/setupEnvFiles.mjs +31 -0
- package/dist/lib/smokeTests/artifacts.d.mts +10 -0
- package/dist/lib/smokeTests/artifacts.mjs +164 -0
- package/dist/lib/smokeTests/browser.d.mts +48 -0
- package/dist/lib/smokeTests/browser.mjs +1041 -0
- package/dist/lib/smokeTests/cleanup.d.mts +5 -0
- package/dist/lib/smokeTests/cleanup.mjs +214 -0
- package/dist/lib/smokeTests/codeUpdates.d.mts +8 -0
- package/dist/lib/smokeTests/codeUpdates.mjs +229 -0
- package/dist/lib/smokeTests/constants.d.mts +5 -0
- package/dist/lib/smokeTests/constants.mjs +10 -0
- package/dist/lib/smokeTests/development.d.mts +11 -0
- package/dist/lib/smokeTests/development.mjs +209 -0
- package/dist/lib/smokeTests/environment.d.mts +14 -0
- package/dist/lib/smokeTests/environment.mjs +163 -0
- package/dist/lib/smokeTests/release.d.mts +61 -0
- package/dist/lib/smokeTests/release.mjs +526 -0
- package/dist/lib/smokeTests/reporting.d.mts +13 -0
- package/dist/lib/smokeTests/reporting.mjs +355 -0
- package/dist/lib/smokeTests/runSmokeTests.d.mts +5 -0
- package/dist/lib/smokeTests/runSmokeTests.mjs +144 -0
- package/dist/lib/smokeTests/state.d.mts +48 -0
- package/dist/lib/smokeTests/state.mjs +57 -0
- package/dist/lib/smokeTests/templates/SmokeTest.template.d.ts +1 -0
- package/dist/lib/smokeTests/templates/SmokeTest.template.js +81 -0
- package/dist/lib/smokeTests/templates/SmokeTestClient.template.d.ts +1 -0
- package/dist/lib/smokeTests/templates/SmokeTestClient.template.js +159 -0
- package/dist/lib/smokeTests/templates/smokeTestFunctions.template.d.ts +1 -0
- package/dist/lib/smokeTests/templates/smokeTestFunctions.template.js +19 -0
- package/dist/lib/smokeTests/types.d.mts +75 -0
- package/dist/lib/smokeTests/utils.d.mts +15 -0
- package/dist/lib/smokeTests/utils.mjs +147 -0
- package/dist/llms/index.d.ts +3 -0
- package/dist/llms/index.js +35 -0
- package/dist/llms/rules/interruptors.d.ts +1 -0
- package/dist/llms/rules/interruptors.js +243 -0
- package/dist/llms/rules/middleware.d.ts +1 -0
- package/dist/llms/rules/middleware.js +71 -0
- package/dist/llms/rules/react.d.ts +1 -0
- package/dist/llms/rules/react.js +106 -0
- package/dist/llms/rules/request-response.d.ts +1 -0
- package/dist/llms/rules/request-response.js +209 -0
- package/dist/runtime/client.d.ts +17 -0
- package/dist/runtime/client.js +74 -0
- package/dist/runtime/clientNavigation.d.ts +4 -0
- package/dist/runtime/clientNavigation.js +53 -0
- package/dist/runtime/clientNavigation.test.d.ts +1 -0
- package/dist/runtime/clientNavigation.test.js +55 -0
- package/dist/runtime/constants.d.ts +1 -0
- package/dist/runtime/constants.js +1 -0
- package/dist/runtime/entries/auth.d.ts +1 -0
- package/dist/runtime/entries/auth.js +1 -0
- package/dist/runtime/entries/client.d.ts +4 -0
- package/dist/runtime/entries/client.js +4 -0
- package/dist/runtime/entries/clientSSR.d.ts +1 -0
- package/dist/runtime/entries/clientSSR.js +1 -0
- package/dist/runtime/entries/no-react-server.d.ts +0 -0
- package/dist/runtime/entries/no-react-server.js +2 -0
- package/dist/runtime/entries/react-server-only.d.ts +0 -0
- package/dist/runtime/entries/react-server-only.js +2 -0
- package/dist/runtime/entries/router.d.ts +2 -0
- package/dist/runtime/entries/router.js +2 -0
- package/dist/runtime/entries/ssr.d.ts +1 -0
- package/dist/runtime/entries/ssr.js +1 -0
- package/dist/runtime/entries/worker.d.ts +9 -0
- package/dist/runtime/entries/worker.js +9 -0
- package/dist/runtime/error.d.ts +6 -0
- package/dist/runtime/error.js +8 -0
- package/dist/runtime/imports/ClientOnly.d.ts +3 -0
- package/dist/runtime/imports/ClientOnly.js +8 -0
- package/dist/runtime/imports/client.d.ts +4 -0
- package/dist/runtime/imports/client.js +33 -0
- package/dist/runtime/imports/ssr.d.ts +5 -0
- package/dist/runtime/imports/ssr.js +20 -0
- package/dist/runtime/imports/worker.d.ts +5 -0
- package/dist/runtime/imports/worker.js +22 -0
- package/dist/runtime/lib/auth/index.d.ts +1 -0
- package/dist/runtime/lib/auth/index.js +1 -0
- package/dist/runtime/lib/auth/session.d.ts +50 -0
- package/dist/runtime/lib/auth/session.js +148 -0
- package/dist/runtime/lib/db/DOWorkerDialect.d.ts +29 -0
- package/dist/runtime/lib/db/DOWorkerDialect.js +66 -0
- package/dist/runtime/lib/db/SqliteDurableObject.d.ts +14 -0
- package/dist/runtime/lib/db/SqliteDurableObject.js +42 -0
- package/dist/runtime/lib/db/createDb.d.ts +2 -0
- package/dist/runtime/lib/db/createDb.js +33 -0
- package/dist/runtime/lib/db/index.d.ts +4 -0
- package/dist/runtime/lib/db/index.js +3 -0
- package/dist/runtime/lib/db/migrations.d.ts +23 -0
- package/dist/runtime/lib/db/migrations.js +34 -0
- package/dist/runtime/lib/db/typeInference/assert.d.ts +2 -0
- package/dist/runtime/lib/db/typeInference/assert.js +1 -0
- package/dist/runtime/lib/db/typeInference/builders/alterColumn.d.ts +27 -0
- package/dist/runtime/lib/db/typeInference/builders/alterColumn.js +1 -0
- package/dist/runtime/lib/db/typeInference/builders/alterTable.d.ts +53 -0
- package/dist/runtime/lib/db/typeInference/builders/alterTable.js +1 -0
- package/dist/runtime/lib/db/typeInference/builders/columnDefinition.d.ts +26 -0
- package/dist/runtime/lib/db/typeInference/builders/columnDefinition.js +1 -0
- package/dist/runtime/lib/db/typeInference/builders/createTable.d.ts +49 -0
- package/dist/runtime/lib/db/typeInference/builders/createTable.js +1 -0
- package/dist/runtime/lib/db/typeInference/builders/createView.d.ts +17 -0
- package/dist/runtime/lib/db/typeInference/builders/createView.js +1 -0
- package/dist/runtime/lib/db/typeInference/builders/dropTable.d.ts +11 -0
- package/dist/runtime/lib/db/typeInference/builders/dropTable.js +1 -0
- package/dist/runtime/lib/db/typeInference/builders/dropView.d.ts +12 -0
- package/dist/runtime/lib/db/typeInference/builders/dropView.js +1 -0
- package/dist/runtime/lib/db/typeInference/builders/schema.d.ts +24 -0
- package/dist/runtime/lib/db/typeInference/builders/schema.js +1 -0
- package/dist/runtime/lib/db/typeInference/database.d.ts +27 -0
- package/dist/runtime/lib/db/typeInference/database.js +1 -0
- package/dist/runtime/lib/db/typeInference/typetests/alterTable.typetest.d.ts +1 -0
- package/dist/runtime/lib/db/typeInference/typetests/alterTable.typetest.js +360 -0
- package/dist/runtime/lib/db/typeInference/typetests/createTable.typetest.d.ts +1 -0
- package/dist/runtime/lib/db/typeInference/typetests/createTable.typetest.js +33 -0
- package/dist/runtime/lib/db/typeInference/typetests/dropTable.typetest.d.ts +1 -0
- package/dist/runtime/lib/db/typeInference/typetests/dropTable.typetest.js +143 -0
- package/dist/runtime/lib/db/typeInference/typetests/print.d.ts +3 -0
- package/dist/runtime/lib/db/typeInference/typetests/print.js +1 -0
- package/dist/runtime/lib/db/typeInference/typetests/testUtils.d.ts +2 -0
- package/dist/runtime/lib/db/typeInference/typetests/testUtils.js +1 -0
- package/dist/runtime/lib/db/typeInference/typetests/typeInference.typetest.d.ts +1 -0
- package/dist/runtime/lib/db/typeInference/typetests/typeInference.typetest.js +17 -0
- package/dist/runtime/lib/db/typeInference/utils.d.ts +82 -0
- package/dist/runtime/lib/db/typeInference/utils.js +2 -0
- package/dist/runtime/lib/debug.d.ts +2 -0
- package/dist/runtime/lib/debug.js +36 -0
- package/dist/runtime/lib/links.d.ts +14 -0
- package/dist/runtime/lib/links.js +38 -0
- package/dist/runtime/lib/realtime/client.d.ts +7 -0
- package/dist/runtime/lib/realtime/client.js +166 -0
- package/dist/runtime/lib/realtime/constants.d.ts +1 -0
- package/dist/runtime/lib/realtime/constants.js +1 -0
- package/dist/runtime/lib/realtime/durableObject.d.ts +29 -0
- package/dist/runtime/lib/realtime/durableObject.js +187 -0
- package/dist/runtime/lib/realtime/renderRealtimeClients.d.ts +7 -0
- package/dist/runtime/lib/realtime/renderRealtimeClients.js +6 -0
- package/dist/runtime/lib/realtime/shared.d.ts +10 -0
- package/dist/runtime/lib/realtime/shared.js +10 -0
- package/dist/runtime/lib/realtime/validateUpgradeRequest.d.ts +6 -0
- package/dist/runtime/lib/realtime/validateUpgradeRequest.js +29 -0
- package/dist/runtime/lib/realtime/worker.d.ts +3 -0
- package/dist/runtime/lib/realtime/worker.js +16 -0
- package/dist/runtime/lib/router.d.ts +56 -0
- package/dist/runtime/lib/router.js +210 -0
- package/dist/runtime/lib/router.test.d.ts +1 -0
- package/dist/runtime/lib/router.test.js +58 -0
- package/dist/runtime/lib/streams/consumeEventStream.d.ts +4 -0
- package/dist/runtime/lib/streams/consumeEventStream.js +13 -0
- package/dist/runtime/lib/turnstile/TurnstileScript.d.ts +1 -0
- package/dist/runtime/lib/turnstile/TurnstileScript.js +2 -0
- package/dist/runtime/lib/turnstile/turnstile.d.ts +3 -0
- package/dist/runtime/lib/turnstile/turnstile.js +3 -0
- package/dist/runtime/lib/turnstile/useTurnstile.d.ts +4 -0
- package/dist/runtime/lib/turnstile/useTurnstile.js +23 -0
- package/dist/runtime/lib/turnstile/verifyTurnstileToken.d.ts +4 -0
- package/dist/runtime/lib/turnstile/verifyTurnstileToken.js +15 -0
- package/dist/runtime/lib/utils.d.ts +1 -0
- package/dist/runtime/lib/utils.js +1 -0
- package/dist/runtime/register/client.d.ts +1 -0
- package/dist/runtime/register/client.js +5 -0
- package/dist/runtime/register/ssr.d.ts +3 -0
- package/dist/runtime/register/ssr.js +26 -0
- package/dist/runtime/register/worker.d.ts +4 -0
- package/dist/runtime/register/worker.js +42 -0
- package/dist/runtime/render/createClientManifest.d.ts +1 -0
- package/dist/runtime/render/createClientManifest.js +7 -0
- package/dist/runtime/render/createModuleMap.d.ts +1 -0
- package/dist/runtime/render/createModuleMap.js +13 -0
- package/dist/runtime/render/renderRscThenableToHtmlStream.d.ts +9 -0
- package/dist/runtime/render/renderRscThenableToHtmlStream.js +49 -0
- package/dist/runtime/render/renderToRscStream.d.ts +5 -0
- package/dist/runtime/render/renderToRscStream.js +46 -0
- package/dist/runtime/render/renderToStream.d.ts +9 -0
- package/dist/runtime/render/renderToStream.js +27 -0
- package/dist/runtime/render/renderToString.d.ts +7 -0
- package/dist/runtime/render/renderToString.js +26 -0
- package/dist/runtime/render/transformRscToHtmlStream.d.ts +8 -0
- package/dist/runtime/render/transformRscToHtmlStream.js +19 -0
- package/dist/runtime/requestInfo/types.d.ts +11 -0
- package/dist/runtime/requestInfo/types.js +1 -0
- package/dist/runtime/requestInfo/worker.d.ts +5 -0
- package/dist/runtime/requestInfo/worker.js +33 -0
- package/dist/runtime/script.d.ts +5 -0
- package/dist/runtime/script.js +8 -0
- package/dist/runtime/ssrBridge.d.ts +2 -0
- package/dist/runtime/ssrBridge.js +11 -0
- package/dist/runtime/worker.d.ts +18 -0
- package/dist/runtime/worker.js +173 -0
- package/dist/scripts/__sdk.d.mts +1 -0
- package/dist/scripts/__sdk.mjs +14 -0
- package/dist/scripts/debug-sync.d.mts +6 -0
- package/dist/scripts/debug-sync.mjs +224 -0
- package/dist/scripts/dev-init.d.mts +1 -0
- package/dist/scripts/dev-init.mjs +25 -0
- package/dist/scripts/ensure-deploy-env.d.mts +1 -0
- package/dist/scripts/ensure-deploy-env.mjs +271 -0
- package/dist/scripts/ensure-env.d.mts +1 -0
- package/dist/scripts/ensure-env.mjs +9 -0
- package/dist/scripts/migrate-new.d.mts +1 -0
- package/dist/scripts/migrate-new.mjs +51 -0
- package/dist/scripts/smoke-test.d.mts +1 -0
- package/dist/scripts/smoke-test.mjs +166 -0
- package/dist/scripts/worker-run.d.mts +1 -0
- package/dist/scripts/worker-run.mjs +82 -0
- package/dist/vite/checkIsUsingPrisma.d.mts +6 -0
- package/dist/vite/checkIsUsingPrisma.mjs +18 -0
- package/dist/vite/configPlugin.d.mts +9 -0
- package/dist/vite/configPlugin.mjs +169 -0
- package/dist/vite/createDirectiveLookupPlugin.d.mts +21 -0
- package/dist/vite/createDirectiveLookupPlugin.mjs +231 -0
- package/dist/vite/devServerTimingPlugin.d.mts +2 -0
- package/dist/vite/devServerTimingPlugin.mjs +24 -0
- package/dist/vite/directivesPlugin.d.mts +6 -0
- package/dist/vite/directivesPlugin.mjs +200 -0
- package/dist/vite/ensureAliasArray.d.mts +2 -0
- package/dist/vite/ensureAliasArray.mjs +17 -0
- package/dist/vite/findSpecifiers.d.mts +31 -0
- package/dist/vite/findSpecifiers.mjs +230 -0
- package/dist/vite/findSsrSpecifiers.d.mts +11 -0
- package/dist/vite/findSsrSpecifiers.mjs +67 -0
- package/dist/vite/hasDirective.d.mts +7 -0
- package/dist/vite/hasDirective.mjs +54 -0
- package/dist/vite/hasOwnCloudflareVitePlugin.d.mts +3 -0
- package/dist/vite/hasOwnCloudflareVitePlugin.mjs +14 -0
- package/dist/vite/index.d.mts +1 -0
- package/dist/vite/index.mjs +1 -0
- package/dist/vite/injectVitePreamblePlugin.d.mts +4 -0
- package/dist/vite/injectVitePreamblePlugin.mjs +23 -0
- package/dist/vite/invalidateCacheIfPrismaClientChanged.d.mts +3 -0
- package/dist/vite/invalidateCacheIfPrismaClientChanged.mjs +27 -0
- package/dist/vite/invalidateModule.d.mts +6 -0
- package/dist/vite/invalidateModule.mjs +30 -0
- package/dist/vite/miniflareHMRPlugin.d.mts +10 -0
- package/dist/vite/miniflareHMRPlugin.mjs +209 -0
- package/dist/vite/moveStaticAssetsPlugin.d.mts +4 -0
- package/dist/vite/moveStaticAssetsPlugin.mjs +12 -0
- package/dist/vite/normalizeModulePath.d.mts +1 -0
- package/dist/vite/normalizeModulePath.mjs +13 -0
- package/dist/vite/prismaPlugin.d.mts +4 -0
- package/dist/vite/prismaPlugin.mjs +43 -0
- package/dist/vite/reactConditionsResolverPlugin.d.mts +16 -0
- package/dist/vite/reactConditionsResolverPlugin.mjs +179 -0
- package/dist/vite/redwoodPlugin.d.mts +12 -0
- package/dist/vite/redwoodPlugin.mjs +105 -0
- package/dist/vite/ssrBridgePlugin.d.mts +7 -0
- package/dist/vite/ssrBridgePlugin.mjs +137 -0
- package/dist/vite/transformClientComponents.d.mts +12 -0
- package/dist/vite/transformClientComponents.mjs +116 -0
- package/dist/vite/transformClientComponents.test.d.mts +1 -0
- package/dist/vite/transformClientComponents.test.mjs +264 -0
- package/dist/vite/transformJsxScriptTagsPlugin.d.mts +8 -0
- package/dist/vite/transformJsxScriptTagsPlugin.mjs +315 -0
- package/dist/vite/transformJsxScriptTagsPlugin.test.d.mts +1 -0
- package/dist/vite/transformJsxScriptTagsPlugin.test.mjs +334 -0
- package/dist/vite/transformServerFunctions.d.mts +16 -0
- package/dist/vite/transformServerFunctions.mjs +296 -0
- package/dist/vite/transformServerFunctions.test.d.mts +1 -0
- package/dist/vite/transformServerFunctions.test.mjs +124 -0
- package/dist/vite/useClientLookupPlugin.d.mts +5 -0
- package/dist/vite/useClientLookupPlugin.mjs +15 -0
- package/dist/vite/useServerLookupPlugin.d.mts +5 -0
- package/dist/vite/useServerLookupPlugin.mjs +15 -0
- package/dist/vite/useServerPlugin.d.mts +1 -0
- package/dist/vite/useServerPlugin.mjs +1 -0
- package/dist/vite/virtualPlugin.d.mts +2 -0
- package/dist/vite/virtualPlugin.mjs +18 -0
- package/dist/vite/vitePreamblePlugin.d.mts +1 -0
- package/dist/vite/vitePreamblePlugin.mjs +11 -0
- package/package.json +1 -1
- package/dist/runtime/lib/db/typeInference/builders/table.d.ts +0 -10
- package/dist/vite/invalidateClientModule.d.mts +0 -2
- package/dist/vite/invalidateClientModule.mjs +0 -8
- package/dist/vite/invalidateModule copy.d.mts +0 -2
- package/dist/vite/invalidateModule copy.mjs +0 -14
- package/dist/vite/invalidateSSRModule.d.mts +0 -2
- package/dist/vite/invalidateSSRModule.mjs +0 -7
- package/dist/vite/mode.d.mts +0 -5
- package/dist/vite/mode.mjs +0 -25
- package/dist/vite/modePlugin.d.mts +0 -2
- package/dist/vite/modePlugin.mjs +0 -10
- /package/dist/{runtime/lib/db/typeInference/builders/table.js → lib/smokeTests/types.mjs} +0 -0
- /package/dist/vite/{isJsFile.d.ts → isJsFile.d.mts} +0 -0
- /package/dist/vite/{isJsFile.js → isJsFile.mjs} +0 -0
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { Project, Node, SyntaxKind } from "ts-morph";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { pathExists } from "fs-extra";
|
|
4
|
+
let manifestCache;
|
|
5
|
+
const readManifest = async (manifestPath) => {
|
|
6
|
+
if (manifestCache === undefined) {
|
|
7
|
+
const exists = await pathExists(manifestPath);
|
|
8
|
+
if (!exists) {
|
|
9
|
+
throw new Error(`RedwoodSDK expected client manifest to exist at ${manifestPath}. This is likely a bug. Please report it at https://github.com/redwoodjs/sdk/issues/new`);
|
|
10
|
+
}
|
|
11
|
+
manifestCache = JSON.parse(await readFile(manifestPath, "utf-8"));
|
|
12
|
+
}
|
|
13
|
+
return manifestCache;
|
|
14
|
+
};
|
|
15
|
+
function hasJsxFunctions(text) {
|
|
16
|
+
return (text.includes('jsx("script"') ||
|
|
17
|
+
text.includes("jsx('script'") ||
|
|
18
|
+
text.includes('jsx("link"') ||
|
|
19
|
+
text.includes("jsx('link'") ||
|
|
20
|
+
text.includes('jsxs("script"') ||
|
|
21
|
+
text.includes("jsxs('script'") ||
|
|
22
|
+
text.includes('jsxs("link"') ||
|
|
23
|
+
text.includes("jsxs('link'") ||
|
|
24
|
+
text.includes('jsxDEV("script"') ||
|
|
25
|
+
text.includes("jsxDEV('script'") ||
|
|
26
|
+
text.includes('jsxDEV("link"') ||
|
|
27
|
+
text.includes("jsxDEV('link'"));
|
|
28
|
+
}
|
|
29
|
+
// Transform import statements in script content using ts-morph
|
|
30
|
+
function transformScriptImports(scriptContent, manifest) {
|
|
31
|
+
const scriptProject = new Project({ useInMemoryFileSystem: true });
|
|
32
|
+
try {
|
|
33
|
+
// Wrap in a function to make it valid JavaScript
|
|
34
|
+
const wrappedContent = `function __wrapper() {${scriptContent}}`;
|
|
35
|
+
const scriptFile = scriptProject.createSourceFile("script.js", wrappedContent);
|
|
36
|
+
let hasChanges = false;
|
|
37
|
+
// Find all CallExpressions that look like import("path")
|
|
38
|
+
scriptFile
|
|
39
|
+
.getDescendantsOfKind(SyntaxKind.CallExpression)
|
|
40
|
+
.forEach((callExpr) => {
|
|
41
|
+
const expr = callExpr.getExpression();
|
|
42
|
+
// Check for both "import()" and "await import()" patterns
|
|
43
|
+
const isImport = expr.getText() === "import";
|
|
44
|
+
// Check for await import pattern
|
|
45
|
+
const isAwaitImport = expr.getKind() === SyntaxKind.PropertyAccessExpression &&
|
|
46
|
+
expr.getText().endsWith(".import");
|
|
47
|
+
if (isImport || isAwaitImport) {
|
|
48
|
+
const args = callExpr.getArguments();
|
|
49
|
+
if (args.length > 0 && Node.isStringLiteral(args[0])) {
|
|
50
|
+
const importPath = args[0].getLiteralValue();
|
|
51
|
+
if (importPath.startsWith("/")) {
|
|
52
|
+
const path = importPath.slice(1); // Remove leading slash
|
|
53
|
+
if (manifest[path]) {
|
|
54
|
+
const transformedPath = manifest[path].file;
|
|
55
|
+
args[0].replaceWithText(`"/${transformedPath}"`);
|
|
56
|
+
hasChanges = true;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
if (hasChanges) {
|
|
63
|
+
// Extract the transformed content from inside the wrapper function
|
|
64
|
+
const fullText = scriptFile.getFullText();
|
|
65
|
+
// Find content between the first { and the last }
|
|
66
|
+
const startPos = fullText.indexOf("{") + 1;
|
|
67
|
+
const endPos = fullText.lastIndexOf("}");
|
|
68
|
+
const transformedContent = fullText.substring(startPos, endPos);
|
|
69
|
+
return { content: transformedContent, hasChanges: true };
|
|
70
|
+
}
|
|
71
|
+
// Return the original content when no changes are made
|
|
72
|
+
return { content: scriptContent, hasChanges: false };
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
// If parsing fails, fall back to the original content
|
|
76
|
+
console.warn("Failed to parse inline script content:", error);
|
|
77
|
+
return { content: undefined, hasChanges: false };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
export async function transformJsxScriptTagsCode(code, manifest = {}) {
|
|
81
|
+
// context(justinvdm, 15 Jun 2025): Optimization to exit early
|
|
82
|
+
// to avoidunnecessary ts-morph parsing
|
|
83
|
+
if (!hasJsxFunctions(code)) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const project = new Project({ useInMemoryFileSystem: true });
|
|
87
|
+
const sourceFile = project.createSourceFile("temp.tsx", code);
|
|
88
|
+
let hasModifications = false;
|
|
89
|
+
let needsRequestInfoImport = false;
|
|
90
|
+
// Check for existing imports up front
|
|
91
|
+
let hasRequestInfoImport = false;
|
|
92
|
+
let sdkWorkerImportDecl;
|
|
93
|
+
// Scan for imports only once
|
|
94
|
+
sourceFile.getImportDeclarations().forEach((importDecl) => {
|
|
95
|
+
const moduleSpecifier = importDecl.getModuleSpecifierValue();
|
|
96
|
+
if (moduleSpecifier === "rwsdk/worker") {
|
|
97
|
+
sdkWorkerImportDecl = importDecl;
|
|
98
|
+
// Check if requestInfo is already imported
|
|
99
|
+
if (importDecl
|
|
100
|
+
.getNamedImports()
|
|
101
|
+
.some((namedImport) => namedImport.getName() === "requestInfo")) {
|
|
102
|
+
hasRequestInfoImport = true;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
// Look for jsx function calls (jsx, jsxs, jsxDEV)
|
|
107
|
+
sourceFile
|
|
108
|
+
.getDescendantsOfKind(SyntaxKind.CallExpression)
|
|
109
|
+
.forEach((callExpr) => {
|
|
110
|
+
const expression = callExpr.getExpression();
|
|
111
|
+
const expressionText = expression.getText();
|
|
112
|
+
// Only process jsx/jsxs/jsxDEV calls
|
|
113
|
+
if (expressionText !== "jsx" &&
|
|
114
|
+
expressionText !== "jsxs" &&
|
|
115
|
+
expressionText !== "jsxDEV") {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
// Get arguments of the jsx call
|
|
119
|
+
const args = callExpr.getArguments();
|
|
120
|
+
if (args.length < 2)
|
|
121
|
+
return;
|
|
122
|
+
// First argument should be the element type
|
|
123
|
+
const elementType = args[0];
|
|
124
|
+
if (!Node.isStringLiteral(elementType))
|
|
125
|
+
return;
|
|
126
|
+
const tagName = elementType.getLiteralValue();
|
|
127
|
+
// Process script and link tags
|
|
128
|
+
if (tagName === "script" || tagName === "link") {
|
|
129
|
+
// Second argument should be the props object
|
|
130
|
+
const propsArg = args[1];
|
|
131
|
+
// Handle object literals with properties
|
|
132
|
+
if (Node.isObjectLiteralExpression(propsArg)) {
|
|
133
|
+
const properties = propsArg.getProperties();
|
|
134
|
+
// Variables to track script attributes
|
|
135
|
+
let hasDangerouslySetInnerHTML = false;
|
|
136
|
+
let hasNonce = false;
|
|
137
|
+
let hasStringLiteralChildren = false;
|
|
138
|
+
let hasSrc = false;
|
|
139
|
+
// Variables to track link attributes
|
|
140
|
+
let isPreload = false;
|
|
141
|
+
let hrefValue = null;
|
|
142
|
+
for (const prop of properties) {
|
|
143
|
+
if (Node.isPropertyAssignment(prop)) {
|
|
144
|
+
const propName = prop.getName();
|
|
145
|
+
const initializer = prop.getInitializer();
|
|
146
|
+
// Check for existing nonce
|
|
147
|
+
if (propName === "nonce") {
|
|
148
|
+
hasNonce = true;
|
|
149
|
+
}
|
|
150
|
+
// Check for dangerouslySetInnerHTML
|
|
151
|
+
if (propName === "dangerouslySetInnerHTML") {
|
|
152
|
+
hasDangerouslySetInnerHTML = true;
|
|
153
|
+
}
|
|
154
|
+
// Check for src attribute
|
|
155
|
+
if (tagName === "script" && propName === "src") {
|
|
156
|
+
hasSrc = true;
|
|
157
|
+
// Also process src for manifest transformation if needed
|
|
158
|
+
if (Node.isStringLiteral(initializer) ||
|
|
159
|
+
Node.isNoSubstitutionTemplateLiteral(initializer)) {
|
|
160
|
+
const srcValue = initializer.getLiteralValue();
|
|
161
|
+
if (srcValue.startsWith("/") && manifest[srcValue.slice(1)]) {
|
|
162
|
+
const path = srcValue.slice(1); // Remove leading slash
|
|
163
|
+
const transformedSrc = manifest[path].file;
|
|
164
|
+
const originalText = initializer.getText();
|
|
165
|
+
const isTemplateLiteral = Node.isNoSubstitutionTemplateLiteral(initializer);
|
|
166
|
+
const quote = isTemplateLiteral
|
|
167
|
+
? "`"
|
|
168
|
+
: originalText.charAt(0);
|
|
169
|
+
// Preserve the original quote style
|
|
170
|
+
if (isTemplateLiteral) {
|
|
171
|
+
initializer.replaceWithText(`\`/${transformedSrc}\``);
|
|
172
|
+
}
|
|
173
|
+
else if (quote === '"') {
|
|
174
|
+
initializer.replaceWithText(`"/${transformedSrc}"`);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
initializer.replaceWithText(`'/${transformedSrc}'`);
|
|
178
|
+
}
|
|
179
|
+
hasModifications = true;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// Check for string literal children
|
|
184
|
+
if (tagName === "script" &&
|
|
185
|
+
propName === "children" &&
|
|
186
|
+
(Node.isStringLiteral(initializer) ||
|
|
187
|
+
Node.isNoSubstitutionTemplateLiteral(initializer))) {
|
|
188
|
+
hasStringLiteralChildren = true;
|
|
189
|
+
const scriptContent = initializer.getLiteralValue();
|
|
190
|
+
// Transform import statements in script content using ts-morph
|
|
191
|
+
const { content: transformedContent, hasChanges } = transformScriptImports(scriptContent, manifest);
|
|
192
|
+
if (hasChanges && transformedContent) {
|
|
193
|
+
// Get the raw text with quotes to determine the exact format
|
|
194
|
+
const isTemplateLiteral = Node.isNoSubstitutionTemplateLiteral(initializer);
|
|
195
|
+
if (isTemplateLiteral) {
|
|
196
|
+
// Simply wrap the transformed content in backticks
|
|
197
|
+
initializer.replaceWithText("`" + transformedContent + "`");
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
initializer.replaceWithText(JSON.stringify(transformedContent));
|
|
201
|
+
}
|
|
202
|
+
hasModifications = true;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// For link tags, first check if it's a preload/modulepreload
|
|
206
|
+
if (tagName === "link") {
|
|
207
|
+
if (propName === "rel" &&
|
|
208
|
+
(Node.isStringLiteral(initializer) ||
|
|
209
|
+
Node.isNoSubstitutionTemplateLiteral(initializer))) {
|
|
210
|
+
const relValue = initializer.getLiteralValue();
|
|
211
|
+
if (relValue === "preload" || relValue === "modulepreload") {
|
|
212
|
+
isPreload = true;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (propName === "href" &&
|
|
216
|
+
(Node.isStringLiteral(initializer) ||
|
|
217
|
+
Node.isNoSubstitutionTemplateLiteral(initializer))) {
|
|
218
|
+
hrefValue = initializer.getLiteralValue();
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// Add nonce to script tags if needed
|
|
224
|
+
if (tagName === "script" &&
|
|
225
|
+
!hasNonce &&
|
|
226
|
+
!hasDangerouslySetInnerHTML &&
|
|
227
|
+
(hasStringLiteralChildren || hasSrc)) {
|
|
228
|
+
// Add nonce property to the props object
|
|
229
|
+
propsArg.addPropertyAssignment({
|
|
230
|
+
name: "nonce",
|
|
231
|
+
initializer: "requestInfo.rw.nonce",
|
|
232
|
+
});
|
|
233
|
+
if (!hasRequestInfoImport) {
|
|
234
|
+
needsRequestInfoImport = true;
|
|
235
|
+
}
|
|
236
|
+
hasModifications = true;
|
|
237
|
+
}
|
|
238
|
+
// Transform href if this is a preload link
|
|
239
|
+
if (tagName === "link" &&
|
|
240
|
+
isPreload &&
|
|
241
|
+
hrefValue &&
|
|
242
|
+
hrefValue.startsWith("/") &&
|
|
243
|
+
manifest[hrefValue.slice(1)]) {
|
|
244
|
+
const path = hrefValue.slice(1); // Remove leading slash
|
|
245
|
+
for (const prop of properties) {
|
|
246
|
+
if (Node.isPropertyAssignment(prop) &&
|
|
247
|
+
prop.getName() === "href") {
|
|
248
|
+
const initializer = prop.getInitializer();
|
|
249
|
+
if (Node.isStringLiteral(initializer) ||
|
|
250
|
+
Node.isNoSubstitutionTemplateLiteral(initializer)) {
|
|
251
|
+
const transformedHref = manifest[path].file;
|
|
252
|
+
const originalText = initializer.getText();
|
|
253
|
+
const isTemplateLiteral = Node.isNoSubstitutionTemplateLiteral(initializer);
|
|
254
|
+
const quote = isTemplateLiteral
|
|
255
|
+
? "`"
|
|
256
|
+
: originalText.charAt(0);
|
|
257
|
+
// Preserve the original quote style
|
|
258
|
+
if (isTemplateLiteral) {
|
|
259
|
+
initializer.replaceWithText(`\`/${transformedHref}\``);
|
|
260
|
+
}
|
|
261
|
+
else if (quote === '"') {
|
|
262
|
+
initializer.replaceWithText(`"/${transformedHref}"`);
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
initializer.replaceWithText(`'/${transformedHref}'`);
|
|
266
|
+
}
|
|
267
|
+
hasModifications = true;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
// Add requestInfo import if needed and not already imported
|
|
276
|
+
if (needsRequestInfoImport && hasModifications) {
|
|
277
|
+
if (sdkWorkerImportDecl) {
|
|
278
|
+
// Module is imported but need to add requestInfo
|
|
279
|
+
if (!hasRequestInfoImport) {
|
|
280
|
+
sdkWorkerImportDecl.addNamedImport("requestInfo");
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
// Add new import declaration
|
|
285
|
+
sourceFile.addImportDeclaration({
|
|
286
|
+
moduleSpecifier: "rwsdk/worker",
|
|
287
|
+
namedImports: ["requestInfo"],
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
// Return the transformed code only if modifications were made
|
|
292
|
+
if (hasModifications) {
|
|
293
|
+
return {
|
|
294
|
+
code: sourceFile.getFullText(),
|
|
295
|
+
map: null,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
export const transformJsxScriptTagsPlugin = ({ manifestPath, }) => {
|
|
301
|
+
let isBuild = false;
|
|
302
|
+
return {
|
|
303
|
+
name: "rwsdk:transform-jsx-script-tags",
|
|
304
|
+
configResolved(config) {
|
|
305
|
+
isBuild = config.command === "build";
|
|
306
|
+
},
|
|
307
|
+
async transform(code) {
|
|
308
|
+
if (this.environment.name !== "worker") {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
const manifest = isBuild ? await readManifest(manifestPath) : {};
|
|
312
|
+
return transformJsxScriptTagsCode(code, manifest);
|
|
313
|
+
},
|
|
314
|
+
};
|
|
315
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { transformJsxScriptTagsCode } from "./transformJsxScriptTagsPlugin.mjs";
|
|
3
|
+
describe("transformJsxScriptTagsCode", () => {
|
|
4
|
+
const mockManifest = {
|
|
5
|
+
"src/client.tsx": { file: "assets/client-a1b2c3d4.js" },
|
|
6
|
+
"src/entry.js": { file: "assets/entry-e5f6g7h8.js" },
|
|
7
|
+
"src/styles.css": { file: "assets/styles-i9j0k1l2.css" },
|
|
8
|
+
};
|
|
9
|
+
it("transforms script src attributes in JSX", async () => {
|
|
10
|
+
const code = `
|
|
11
|
+
jsx("script", {
|
|
12
|
+
src: "/src/client.tsx",
|
|
13
|
+
type: "module"
|
|
14
|
+
})
|
|
15
|
+
`;
|
|
16
|
+
const result = await transformJsxScriptTagsCode(code, mockManifest);
|
|
17
|
+
expect(result?.code).toEqual(`import { requestInfo } from "rwsdk/worker";
|
|
18
|
+
|
|
19
|
+
jsx("script", {
|
|
20
|
+
src: "/assets/client-a1b2c3d4.js",
|
|
21
|
+
type: "module",
|
|
22
|
+
nonce: requestInfo.rw.nonce
|
|
23
|
+
})
|
|
24
|
+
`);
|
|
25
|
+
});
|
|
26
|
+
it("transforms inline scripts with dynamic imports", async () => {
|
|
27
|
+
const code = `
|
|
28
|
+
jsx("script", {
|
|
29
|
+
type: "module",
|
|
30
|
+
children: "import('/src/client.tsx').then(module => { console.log(module); })"
|
|
31
|
+
})
|
|
32
|
+
`;
|
|
33
|
+
const result = await transformJsxScriptTagsCode(code, mockManifest);
|
|
34
|
+
expect(result?.code).toEqual(`import { requestInfo } from "rwsdk/worker";
|
|
35
|
+
|
|
36
|
+
jsx("script", {
|
|
37
|
+
type: "module",
|
|
38
|
+
children: "import(\\"\/assets\/client-a1b2c3d4.js\\").then(module => { console.log(module); })",
|
|
39
|
+
nonce: requestInfo.rw.nonce
|
|
40
|
+
})
|
|
41
|
+
`);
|
|
42
|
+
});
|
|
43
|
+
it("transforms inline scripts with type=module", async () => {
|
|
44
|
+
const code = `
|
|
45
|
+
jsx("script", { type: "module", children: "import('/src/client.tsx')" })
|
|
46
|
+
`;
|
|
47
|
+
const result = await transformJsxScriptTagsCode(code, mockManifest);
|
|
48
|
+
expect(result?.code).toEqual(`import { requestInfo } from "rwsdk/worker";
|
|
49
|
+
|
|
50
|
+
jsx("script", { type: "module", children: "import(\\"\/assets\/client-a1b2c3d4.js\\")",
|
|
51
|
+
nonce: requestInfo.rw.nonce
|
|
52
|
+
})
|
|
53
|
+
`);
|
|
54
|
+
});
|
|
55
|
+
it("transforms inline scripts with multiline content", async () => {
|
|
56
|
+
const code = `
|
|
57
|
+
jsx("script", {
|
|
58
|
+
type: "module",
|
|
59
|
+
children: \`
|
|
60
|
+
// Some comments here
|
|
61
|
+
const init = async () => {
|
|
62
|
+
await import('/src/entry.js');
|
|
63
|
+
console.log('initialized');
|
|
64
|
+
};
|
|
65
|
+
init();
|
|
66
|
+
\`
|
|
67
|
+
})
|
|
68
|
+
`;
|
|
69
|
+
const result = await transformJsxScriptTagsCode(code, mockManifest);
|
|
70
|
+
expect(result?.code).toEqual(`import { requestInfo } from "rwsdk/worker";
|
|
71
|
+
|
|
72
|
+
jsx("script", {
|
|
73
|
+
type: "module",
|
|
74
|
+
children: \`
|
|
75
|
+
// Some comments here
|
|
76
|
+
const init = async () => {
|
|
77
|
+
await import("/assets/entry-e5f6g7h8.js");
|
|
78
|
+
console.log('initialized');
|
|
79
|
+
};
|
|
80
|
+
init();
|
|
81
|
+
\`,
|
|
82
|
+
nonce: requestInfo.rw.nonce
|
|
83
|
+
})
|
|
84
|
+
`);
|
|
85
|
+
});
|
|
86
|
+
it("transforms multiple imports in the same inline script", async () => {
|
|
87
|
+
const code = `
|
|
88
|
+
jsx("script", {
|
|
89
|
+
type: "module",
|
|
90
|
+
children: \`
|
|
91
|
+
import('/src/client.tsx');
|
|
92
|
+
import('/src/entry.js');
|
|
93
|
+
\`
|
|
94
|
+
})
|
|
95
|
+
`;
|
|
96
|
+
const result = await transformJsxScriptTagsCode(code, mockManifest);
|
|
97
|
+
expect(result?.code).toEqual(`import { requestInfo } from "rwsdk/worker";
|
|
98
|
+
|
|
99
|
+
jsx("script", {
|
|
100
|
+
type: "module",
|
|
101
|
+
children: \`
|
|
102
|
+
import("/assets/client-a1b2c3d4.js");
|
|
103
|
+
import("/assets/entry-e5f6g7h8.js");
|
|
104
|
+
\`,
|
|
105
|
+
nonce: requestInfo.rw.nonce
|
|
106
|
+
})
|
|
107
|
+
`);
|
|
108
|
+
});
|
|
109
|
+
it("transforms link href attributes with preload rel", async () => {
|
|
110
|
+
const code = `
|
|
111
|
+
jsx("link", {
|
|
112
|
+
rel: "preload",
|
|
113
|
+
href: "/src/client.tsx",
|
|
114
|
+
as: "script"
|
|
115
|
+
})
|
|
116
|
+
`;
|
|
117
|
+
const result = await transformJsxScriptTagsCode(code, mockManifest);
|
|
118
|
+
expect(result?.code).toEqual(`
|
|
119
|
+
jsx("link", {
|
|
120
|
+
rel: "preload",
|
|
121
|
+
href: "/assets/client-a1b2c3d4.js",
|
|
122
|
+
as: "script"
|
|
123
|
+
})
|
|
124
|
+
`);
|
|
125
|
+
});
|
|
126
|
+
it("transforms link href attributes with modulepreload rel", async () => {
|
|
127
|
+
const code = `
|
|
128
|
+
jsx("link", {
|
|
129
|
+
href: "/src/client.tsx",
|
|
130
|
+
rel: "modulepreload"
|
|
131
|
+
})
|
|
132
|
+
`;
|
|
133
|
+
const result = await transformJsxScriptTagsCode(code, mockManifest);
|
|
134
|
+
expect(result?.code).toEqual(`
|
|
135
|
+
jsx("link", {
|
|
136
|
+
href: "/assets/client-a1b2c3d4.js",
|
|
137
|
+
rel: "modulepreload"
|
|
138
|
+
})
|
|
139
|
+
`);
|
|
140
|
+
});
|
|
141
|
+
it("transforms real-world Document component example", async () => {
|
|
142
|
+
const code = `
|
|
143
|
+
jsx("html", {
|
|
144
|
+
lang: "en",
|
|
145
|
+
children: [
|
|
146
|
+
jsx("head", {
|
|
147
|
+
children: [
|
|
148
|
+
jsx("meta", { charSet: "utf-8" }),
|
|
149
|
+
jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
|
|
150
|
+
jsx("title", { children: "@redwoodjs/starter-standard" }),
|
|
151
|
+
jsx("link", { rel: "modulepreload", href: "/src/client.tsx", as: "script" })
|
|
152
|
+
]
|
|
153
|
+
}),
|
|
154
|
+
jsx("body", {
|
|
155
|
+
children: [
|
|
156
|
+
jsx("div", { id: "root", children: props.children }),
|
|
157
|
+
jsx("script", { children: 'import("/src/client.tsx")' })
|
|
158
|
+
]
|
|
159
|
+
})
|
|
160
|
+
]
|
|
161
|
+
})
|
|
162
|
+
`;
|
|
163
|
+
const result = await transformJsxScriptTagsCode(code, mockManifest);
|
|
164
|
+
expect(result?.code).toEqual(`import { requestInfo } from "rwsdk/worker";
|
|
165
|
+
|
|
166
|
+
jsx("html", {
|
|
167
|
+
lang: "en",
|
|
168
|
+
children: [
|
|
169
|
+
jsx("head", {
|
|
170
|
+
children: [
|
|
171
|
+
jsx("meta", { charSet: "utf-8" }),
|
|
172
|
+
jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
|
|
173
|
+
jsx("title", { children: "@redwoodjs/starter-standard" }),
|
|
174
|
+
jsx("link", { rel: "modulepreload", href: "/assets/client-a1b2c3d4.js", as: "script" })
|
|
175
|
+
]
|
|
176
|
+
}),
|
|
177
|
+
jsx("body", {
|
|
178
|
+
children: [
|
|
179
|
+
jsx("div", { id: "root", children: props.children }),
|
|
180
|
+
jsx("script", { children: "import(\\"\/assets\/client-a1b2c3d4.js\\")",
|
|
181
|
+
nonce: requestInfo.rw.nonce
|
|
182
|
+
})
|
|
183
|
+
]
|
|
184
|
+
})
|
|
185
|
+
]
|
|
186
|
+
})
|
|
187
|
+
`);
|
|
188
|
+
});
|
|
189
|
+
it("returns null when no transformations are needed", async () => {
|
|
190
|
+
const code = `
|
|
191
|
+
jsx("div", { children: "No scripts or links here" })
|
|
192
|
+
`;
|
|
193
|
+
const result = await transformJsxScriptTagsCode(code, mockManifest);
|
|
194
|
+
expect(result).toBeUndefined();
|
|
195
|
+
});
|
|
196
|
+
it("handles paths not found in manifest", async () => {
|
|
197
|
+
const code = `
|
|
198
|
+
jsx("script", {
|
|
199
|
+
src: "/src/non-existent.js",
|
|
200
|
+
type: "module"
|
|
201
|
+
})
|
|
202
|
+
`;
|
|
203
|
+
const result = await transformJsxScriptTagsCode(code, mockManifest);
|
|
204
|
+
expect(result?.code).toEqual(`import { requestInfo } from "rwsdk/worker";
|
|
205
|
+
|
|
206
|
+
jsx("script", {
|
|
207
|
+
src: "/src/non-existent.js",
|
|
208
|
+
type: "module",
|
|
209
|
+
nonce: requestInfo.rw.nonce
|
|
210
|
+
})
|
|
211
|
+
`);
|
|
212
|
+
});
|
|
213
|
+
it("adds nonce to script tags with src attribute and imports requestInfo", async () => {
|
|
214
|
+
const code = `
|
|
215
|
+
jsx("script", {
|
|
216
|
+
src: "/src/client.tsx",
|
|
217
|
+
type: "module"
|
|
218
|
+
})
|
|
219
|
+
`;
|
|
220
|
+
const result = await transformJsxScriptTagsCode(code, mockManifest);
|
|
221
|
+
expect(result?.code).toEqual(`import { requestInfo } from "rwsdk/worker";
|
|
222
|
+
|
|
223
|
+
jsx("script", {
|
|
224
|
+
src: "/assets/client-a1b2c3d4.js",
|
|
225
|
+
type: "module",
|
|
226
|
+
nonce: requestInfo.rw.nonce
|
|
227
|
+
})
|
|
228
|
+
`);
|
|
229
|
+
});
|
|
230
|
+
it("adds nonce to script tags with string literal children", async () => {
|
|
231
|
+
const code = `
|
|
232
|
+
jsx("script", {
|
|
233
|
+
type: "module",
|
|
234
|
+
children: "console.log('hello world')"
|
|
235
|
+
})
|
|
236
|
+
`;
|
|
237
|
+
const result = await transformJsxScriptTagsCode(code, {});
|
|
238
|
+
expect(result?.code).toEqual(`import { requestInfo } from "rwsdk/worker";
|
|
239
|
+
|
|
240
|
+
jsx("script", {
|
|
241
|
+
type: "module",
|
|
242
|
+
children: "console.log('hello world')",
|
|
243
|
+
nonce: requestInfo.rw.nonce
|
|
244
|
+
})
|
|
245
|
+
`);
|
|
246
|
+
});
|
|
247
|
+
it("does not add nonce to script tags with dangerouslySetInnerHTML", async () => {
|
|
248
|
+
const code = `
|
|
249
|
+
jsx("script", {
|
|
250
|
+
type: "module",
|
|
251
|
+
dangerouslySetInnerHTML: { __html: "console.log('hello world')" }
|
|
252
|
+
})
|
|
253
|
+
`;
|
|
254
|
+
const result = await transformJsxScriptTagsCode(code, {});
|
|
255
|
+
expect(result?.code).toEqual(undefined);
|
|
256
|
+
});
|
|
257
|
+
it("does not add nonce to script tags that already have nonce", async () => {
|
|
258
|
+
const code = `
|
|
259
|
+
jsx("script", {
|
|
260
|
+
type: "module",
|
|
261
|
+
children: "console.log('hello world')",
|
|
262
|
+
nonce: "existing-nonce"
|
|
263
|
+
})
|
|
264
|
+
`;
|
|
265
|
+
const result = await transformJsxScriptTagsCode(code, {});
|
|
266
|
+
expect(result?.code).toEqual(undefined);
|
|
267
|
+
});
|
|
268
|
+
it("uses existing requestInfo import if already present", async () => {
|
|
269
|
+
const code = `
|
|
270
|
+
import { foo } from 'bar';
|
|
271
|
+
import { requestInfo, someOtherThing } from "rwsdk/worker";
|
|
272
|
+
|
|
273
|
+
jsx("script", {
|
|
274
|
+
type: "module",
|
|
275
|
+
children: "console.log('hello world')"
|
|
276
|
+
})
|
|
277
|
+
`;
|
|
278
|
+
const result = await transformJsxScriptTagsCode(code, {});
|
|
279
|
+
expect(result?.code).toEqual(`
|
|
280
|
+
import { foo } from 'bar';
|
|
281
|
+
import { requestInfo, someOtherThing } from "rwsdk/worker";
|
|
282
|
+
|
|
283
|
+
jsx("script", {
|
|
284
|
+
type: "module",
|
|
285
|
+
children: "console.log('hello world')",
|
|
286
|
+
nonce: requestInfo.rw.nonce
|
|
287
|
+
})
|
|
288
|
+
`);
|
|
289
|
+
// Ensure we didn't duplicate the import
|
|
290
|
+
const importCount = (result?.code.match(/from "rwsdk\/worker"/g) || [])
|
|
291
|
+
.length;
|
|
292
|
+
expect(importCount).toBe(1);
|
|
293
|
+
});
|
|
294
|
+
it("adds requestInfo to existing SDK import if module already imported", async () => {
|
|
295
|
+
const code = `
|
|
296
|
+
import { foo } from 'bar';
|
|
297
|
+
import { someOtherThing } from "rwsdk/worker";
|
|
298
|
+
|
|
299
|
+
jsx("script", {
|
|
300
|
+
type: "module",
|
|
301
|
+
children: "console.log('hello world')"
|
|
302
|
+
})
|
|
303
|
+
`;
|
|
304
|
+
const result = await transformJsxScriptTagsCode(code, {});
|
|
305
|
+
expect(result?.code).toEqual(`
|
|
306
|
+
import { foo } from 'bar';
|
|
307
|
+
import { someOtherThing, requestInfo } from "rwsdk/worker";
|
|
308
|
+
|
|
309
|
+
jsx("script", {
|
|
310
|
+
type: "module",
|
|
311
|
+
children: "console.log('hello world')",
|
|
312
|
+
nonce: requestInfo.rw.nonce
|
|
313
|
+
})
|
|
314
|
+
`);
|
|
315
|
+
});
|
|
316
|
+
it("works in development mode without a manifest", async () => {
|
|
317
|
+
const code = `
|
|
318
|
+
jsx("script", {
|
|
319
|
+
src: "/src/client.tsx",
|
|
320
|
+
type: "module"
|
|
321
|
+
})
|
|
322
|
+
`;
|
|
323
|
+
// Call without providing manifest (simulating dev mode)
|
|
324
|
+
const result = await transformJsxScriptTagsCode(code);
|
|
325
|
+
expect(result?.code).toEqual(`import { requestInfo } from "rwsdk/worker";
|
|
326
|
+
|
|
327
|
+
jsx("script", {
|
|
328
|
+
src: "/src/client.tsx",
|
|
329
|
+
type: "module",
|
|
330
|
+
nonce: requestInfo.rw.nonce
|
|
331
|
+
})
|
|
332
|
+
`);
|
|
333
|
+
});
|
|
334
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
interface TransformResult {
|
|
2
|
+
code: string;
|
|
3
|
+
map?: any;
|
|
4
|
+
}
|
|
5
|
+
type ExportInfoCompat = {
|
|
6
|
+
localFunctions: Set<string>;
|
|
7
|
+
reExports: Array<{
|
|
8
|
+
localName: string;
|
|
9
|
+
originalName: string;
|
|
10
|
+
moduleSpecifier: string;
|
|
11
|
+
}>;
|
|
12
|
+
};
|
|
13
|
+
export declare const findExportedFunctions: (code: string, normalizedId?: string) => Set<string>;
|
|
14
|
+
export declare const findExportInfo: (code: string, normalizedId?: string) => ExportInfoCompat;
|
|
15
|
+
export declare const transformServerFunctions: (code: string, normalizedId: string, environment: "client" | "worker" | "ssr", serverFiles?: Set<string>, addServerModule?: (environment: string, id: string) => void) => TransformResult | undefined;
|
|
16
|
+
export type { TransformResult };
|