fix(common): resolve script errors when switching sandbox modes (#5555)

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
James George 2025-11-04 15:13:21 +05:30 committed by GitHub
parent 654e18fce9
commit f8cb75895f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 44 additions and 13 deletions

View file

@ -16,10 +16,11 @@ import { v4 as uuidv4 } from "uuid"
import { computed, onMounted, onUnmounted, ref } from "vue"
import { useColorMode } from "~/composables/theming"
import { MODULE_PREFIX } from "~/helpers/scripting"
// Import type definitions as raw strings
import preRequestTypes from "~/types/pre-request.d.ts?raw"
import postRequestTypes from "~/types/post-request.d.ts?raw"
import preRequestTypes from "~/types/pre-request.d.ts?raw"
const props = withDefaults(
defineProps<{
@ -60,8 +61,6 @@ const extraLibRefs = new Map<string, monaco.IDisposable>()
// Track context-specific type definition for this editor instance
const contextTypeDefRef = ref<monaco.IDisposable | null>(null)
const MODULE_PREFIX = "export {};\n" as const
const ensureCompilerOptions = (() => {
let applied = false

View file

@ -239,6 +239,7 @@ import {
makeCollection,
} from "@hoppscotch/data"
import { useService } from "dioc/vue"
import { MODULE_PREFIX_REGEX_JSON_SERIALIZED } from "~/helpers/scripting"
import * as TE from "fp-ts/TaskEither"
import { pipe } from "fp-ts/function"
@ -2832,7 +2833,10 @@ const exportData = async (collection: HoppCollection | TeamCollection) => {
const collectionJSON = JSON.stringify(collection, null, 2)
// Strip `export {};\n` from `testScript` and `preRequestScript` fields
const cleanedCollectionJSON = collectionJSON.replace(/export \{\};\\n/g, "")
const cleanedCollectionJSON = collectionJSON.replace(
MODULE_PREFIX_REGEX_JSON_SERIALIZED,
""
)
const name = (collection as HoppCollection).name
@ -2855,7 +2859,7 @@ const exportData = async (collection: HoppCollection | TeamCollection) => {
// Strip `export {};\n` from `testScript` and `preRequestScript` fields
const cleanedCollectionJSON = collectionJSONString.replace(
/export \{\};\\n/g,
MODULE_PREFIX_REGEX_JSON_SERIALIZED,
""
)

View file

@ -44,6 +44,7 @@ import { isJSONContentType } from "@helpers/utils/contenttypes"
import { useStreamSubscriber } from "@composables/stream"
import { Completer } from "@helpers/editor/completion"
import { LinterDefinition } from "@helpers/editor/linting/linter"
import { MODULE_PREFIX } from "@helpers/scripting"
import {
basicSetup,
baseTheme,
@ -268,14 +269,12 @@ const getEditorLanguage = (
completer: Completer | undefined
): Extension => hoppLang(getLanguage(langMime) ?? undefined, linter, completer)
const MODULE_PREFIX = "export {};\n" as const
/**
* Strips the `export {};\n` prefix from the value for display in the editor.
* The above is only used internally for Monaco editor's module scope,
* The prefix is used internally for Monaco editor's module scope,
* and should not be visible in the CodeMirror editor.
*/
const stripModulePrefix = (value?: string): string | undefined => {
const stripModulePrefixForDisplay = (value?: string): string | undefined => {
return value?.startsWith(MODULE_PREFIX)
? value.slice(MODULE_PREFIX.length)
: value
@ -488,7 +487,7 @@ export function useCodemirror(
parent: el,
state: EditorState.create({
doc: parseDoc(
stripModulePrefix(value.value),
stripModulePrefixForDisplay(value.value),
options.extendedEditorConfig.mode ?? ""
),
extensions,
@ -532,7 +531,7 @@ export function useCodemirror(
}
// Strip `export {};\n` before displaying in CodeMirror
const displayValue = stripModulePrefix(newVal) ?? ""
const displayValue = stripModulePrefixForDisplay(newVal) ?? ""
if (cachedValue.value !== newVal) {
view.value?.dispatch({

View file

@ -27,6 +27,7 @@ import { map } from "fp-ts/Either"
import { runPreRequestScript, runTestScript } from "@hoppscotch/js-sandbox/web"
import { useSetting } from "~/composables/settings"
import { getService } from "~/modules/dioc"
import { stripModulePrefix } from "~/helpers/scripting"
import {
environmentsStore,
getCurrentEnvironment,
@ -306,7 +307,10 @@ const delegatePreRequestScriptRunner = (
const { preRequestScript } = request
if (!EXPERIMENTAL_SCRIPTING_SANDBOX.value) {
return runPreRequestScript(preRequestScript, {
// Strip `export {};\n` before executing in legacy sandbox to prevent syntax errors
const cleanScript = stripModulePrefix(preRequestScript)
return runPreRequestScript(cleanScript, {
envs,
experimentalScriptingSandbox: false,
})
@ -352,7 +356,10 @@ const runPostRequestScript = (
const { testScript } = request
if (!EXPERIMENTAL_SCRIPTING_SANDBOX.value) {
return runTestScript(testScript, {
// Strip `export {};\n` before executing in legacy sandbox to prevent syntax errors
const cleanScript = stripModulePrefix(testScript)
return runTestScript(cleanScript, {
envs,
response,
experimentalScriptingSandbox: false,

View file

@ -0,0 +1,22 @@
/**
* Module prefix added by Monaco editor for TypeScript module mode.
* Enables IntelliSense and isolates variables across editor instances.
*/
export const MODULE_PREFIX = "export {};\n" as const
/**
* Strips `export {};\n` prefix from scripts before legacy sandbox execution
* (non-module context) or when exporting collections.
*/
export const stripModulePrefix = (script: string): string => {
return script.startsWith(MODULE_PREFIX)
? script.slice(MODULE_PREFIX.length)
: script
}
/**
* Regex for stripping the JSON-serialized module prefix (`export {};\\n`)
* from scripts during collection exports.
* Note: This matches the literal backslash-n (`\\n`), not an actual newline character.
*/
export const MODULE_PREFIX_REGEX_JSON_SERIALIZED = /export \{\};\\n/g