]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler-sfc): check lang before attempt to compile script (#13508)
authorAlex Snezhko <alexsnezhko89@gmail.com>
Tue, 2 Sep 2025 09:39:29 +0000 (02:39 -0700)
committerGitHub <noreply@github.com>
Tue, 2 Sep 2025 09:39:29 +0000 (17:39 +0800)
close #8368

packages/compiler-sfc/__tests__/compileScript.spec.ts
packages/compiler-sfc/src/compileScript.ts
packages/compiler-sfc/src/script/context.ts
packages/compiler-sfc/src/script/normalScript.ts
packages/compiler-sfc/src/script/utils.ts

index f28ed54339265e0039abc78a327b11113882a58f..b69bbca2e16711de636740d9b129e58f59c74b7e 100644 (file)
@@ -1550,4 +1550,19 @@ describe('compileScript', () => {
     )
     assertCode(content)
   })
+
+  test('should not compile unrecognized language', () => {
+    const { content, lang, scriptAst } = compile(
+      `<script lang="coffee">
+      export default
+        data: ->
+          myVal: 0
+      </script>`,
+    )
+    expect(content).toMatch(`export default
+        data: ->
+          myVal: 0`)
+    expect(lang).toBe('coffee')
+    expect(scriptAst).not.toBeDefined()
+  })
 })
index fa81da4233e4d7067b4692430ded6e09561c91bc..cbd4abdf71a2213e4f30f6c3f1bd9444987b48fe 100644 (file)
@@ -56,7 +56,13 @@ import { DEFINE_EXPOSE, processDefineExpose } from './script/defineExpose'
 import { DEFINE_OPTIONS, processDefineOptions } from './script/defineOptions'
 import { DEFINE_SLOTS, processDefineSlots } from './script/defineSlots'
 import { DEFINE_MODEL, processDefineModel } from './script/defineModel'
-import { getImportedName, isCallOf, isLiteralNode } from './script/utils'
+import {
+  getImportedName,
+  isCallOf,
+  isJS,
+  isLiteralNode,
+  isTS,
+} from './script/utils'
 import { analyzeScriptBindings } from './script/analyzeScriptBindings'
 import { isImportUsed } from './script/importUsageCheck'
 import { processAwait } from './script/topLevelAwait'
@@ -173,6 +179,8 @@ export function compileScript(
   const scopeId = options.id ? options.id.replace(/^data-v-/, '') : ''
   const scriptLang = script && script.lang
   const scriptSetupLang = scriptSetup && scriptSetup.lang
+  const isJSOrTS =
+    isJS(scriptLang, scriptSetupLang) || isTS(scriptLang, scriptSetupLang)
 
   if (script && scriptSetup && scriptLang !== scriptSetupLang) {
     throw new Error(
@@ -181,21 +189,28 @@ export function compileScript(
     )
   }
 
-  const ctx = new ScriptCompileContext(sfc, options)
-
   if (!scriptSetup) {
     if (!script) {
       throw new Error(`[@vue/compiler-sfc] SFC contains no <script> tags.`)
     }
+
     // normal <script> only
+    if (script.lang && !isJSOrTS) {
+      // do not process non js/ts script blocks
+      return script
+    }
+
+    const ctx = new ScriptCompileContext(sfc, options)
     return processNormalScript(ctx, scopeId)
   }
 
-  if (scriptSetupLang && !ctx.isJS && !ctx.isTS) {
+  if (scriptSetupLang && !isJSOrTS) {
     // do not process non js/ts script blocks
     return scriptSetup
   }
 
+  const ctx = new ScriptCompileContext(sfc, options)
+
   // metadata that needs to be returned
   // const ctx.bindingMetadata: BindingMetadata = {}
   const scriptBindings: Record<string, BindingTypes> = Object.create(null)
index 47b6b442a492ce092224be86472e7952cf4035ea..3d6a129161f154e065e78ac9a491997b29a653aa 100644 (file)
@@ -9,6 +9,7 @@ import type { BindingMetadata } from '../../../compiler-core/src'
 import MagicString from 'magic-string'
 import type { TypeScope } from './resolveType'
 import { warn } from '../warn'
+import { isJS, isTS } from './utils'
 
 export class ScriptCompileContext {
   isJS: boolean
@@ -87,16 +88,8 @@ export class ScriptCompileContext {
     const scriptLang = script && script.lang
     const scriptSetupLang = scriptSetup && scriptSetup.lang
 
-    this.isJS =
-      scriptLang === 'js' ||
-      scriptLang === 'jsx' ||
-      scriptSetupLang === 'js' ||
-      scriptSetupLang === 'jsx'
-    this.isTS =
-      scriptLang === 'ts' ||
-      scriptLang === 'tsx' ||
-      scriptSetupLang === 'ts' ||
-      scriptSetupLang === 'tsx'
+    this.isJS = isJS(scriptLang, scriptSetupLang)
+    this.isTS = isTS(scriptLang, scriptSetupLang)
 
     const customElement = options.customElement
     const filename = this.descriptor.filename
index 7fd859290b1b9fa975daf5ba6ea90a5785792e96..b019fe110d871a339567e41b07b75f6c8418b2ca 100644 (file)
@@ -12,10 +12,6 @@ export function processNormalScript(
   scopeId: string,
 ): SFCScriptBlock {
   const script = ctx.descriptor.script!
-  if (script.lang && !ctx.isJS && !ctx.isTS) {
-    // do not process non js/ts script blocks
-    return script
-  }
   try {
     let content = script.content
     let map = script.map
index 39f163c6b77d9a8b5a071be5ba3e5a79e7bb33de..1b7da0e349793dadfe6d47ffcb0076e4e00e6a79 100644 (file)
@@ -121,3 +121,8 @@ export const propNameEscapeSymbolsRE: RegExp =
 export function getEscapedPropName(key: string): string {
   return propNameEscapeSymbolsRE.test(key) ? JSON.stringify(key) : key
 }
+
+export const isJS = (...langs: (string | null | undefined)[]): boolean =>
+  langs.some(lang => lang === 'js' || lang === 'jsx')
+export const isTS = (...langs: (string | null | undefined)[]): boolean =>
+  langs.some(lang => lang === 'ts' || lang === 'tsx')