Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions packages/compiler-sfc/__tests__/compileScript.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1543,4 +1543,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()
})
})
22 changes: 19 additions & 3 deletions packages/compiler-sfc/src/compileScript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,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'
Expand Down Expand Up @@ -167,18 +173,26 @@ export function compileScript(
)
}

const ctx = new ScriptCompileContext(sfc, options)
const { script, scriptSetup, source, filename } = sfc
const hoistStatic = options.hoistStatic !== false && !script
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 (!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)
}

Expand All @@ -189,11 +203,13 @@ export function compileScript(
)
}

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)
Expand Down
13 changes: 3 additions & 10 deletions packages/compiler-sfc/src/script/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
4 changes: 0 additions & 4 deletions packages/compiler-sfc/src/script/normalScript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions packages/compiler-sfc/src/script/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')