Browse Source

fix(compiler-sfc): check lang before attempt to compile script (#13508)

close #8368
Alex Snezhko 9 months ago
parent
commit
55922ff316

+ 15 - 0
packages/compiler-sfc/__tests__/compileScript.spec.ts

@@ -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()
+  })
 })

+ 19 - 4
packages/compiler-sfc/src/compileScript.ts

@@ -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)

+ 3 - 10
packages/compiler-sfc/src/script/context.ts

@@ -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

+ 0 - 4
packages/compiler-sfc/src/script/normalScript.ts

@@ -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

+ 5 - 0
packages/compiler-sfc/src/script/utils.ts

@@ -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')