compileScript.ts 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293
  1. import {
  2. BindingTypes,
  3. UNREF,
  4. isFunctionType,
  5. unwrapTSNode,
  6. walkIdentifiers,
  7. } from '@vue/compiler-dom'
  8. import {
  9. DEFAULT_FILENAME,
  10. type SFCDescriptor,
  11. type SFCScriptBlock,
  12. } from './parse'
  13. import type { ParserPlugin } from '@babel/parser'
  14. import { generateCodeFrame } from '@vue/shared'
  15. import type {
  16. ArrayPattern,
  17. CallExpression,
  18. Declaration,
  19. ExportSpecifier,
  20. Identifier,
  21. Node,
  22. ObjectPattern,
  23. Statement,
  24. } from '@babel/types'
  25. import { walk } from 'estree-walker'
  26. import type { RawSourceMap } from 'source-map-js'
  27. import {
  28. normalScriptDefaultVar,
  29. processNormalScript,
  30. } from './script/normalScript'
  31. import { CSS_VARS_HELPER, genCssVarsCode } from './style/cssVars'
  32. import {
  33. type SFCTemplateCompileOptions,
  34. compileTemplate,
  35. } from './compileTemplate'
  36. import { warnOnce } from './warn'
  37. import { transformDestructuredProps } from './script/definePropsDestructure'
  38. import { ScriptCompileContext } from './script/context'
  39. import {
  40. DEFINE_PROPS,
  41. WITH_DEFAULTS,
  42. genRuntimeProps,
  43. processDefineProps,
  44. } from './script/defineProps'
  45. import {
  46. DEFINE_EMITS,
  47. genRuntimeEmits,
  48. processDefineEmits,
  49. } from './script/defineEmits'
  50. import { DEFINE_EXPOSE, processDefineExpose } from './script/defineExpose'
  51. import { DEFINE_OPTIONS, processDefineOptions } from './script/defineOptions'
  52. import { DEFINE_SLOTS, processDefineSlots } from './script/defineSlots'
  53. import { DEFINE_MODEL, processDefineModel } from './script/defineModel'
  54. import { getImportedName, isCallOf, isLiteralNode } from './script/utils'
  55. import { analyzeScriptBindings } from './script/analyzeScriptBindings'
  56. import { isImportUsed } from './script/importUsageCheck'
  57. import { processAwait } from './script/topLevelAwait'
  58. export interface SFCScriptCompileOptions {
  59. /**
  60. * Scope ID for prefixing injected CSS variables.
  61. * This must be consistent with the `id` passed to `compileStyle`.
  62. */
  63. id: string
  64. /**
  65. * Production mode. Used to determine whether to generate hashed CSS variables
  66. */
  67. isProd?: boolean
  68. /**
  69. * Enable/disable source map. Defaults to true.
  70. */
  71. sourceMap?: boolean
  72. /**
  73. * https://babeljs.io/docs/en/babel-parser#plugins
  74. */
  75. babelParserPlugins?: ParserPlugin[]
  76. /**
  77. * A list of files to parse for global types to be made available for type
  78. * resolving in SFC macros. The list must be fully resolved file system paths.
  79. */
  80. globalTypeFiles?: string[]
  81. /**
  82. * Compile the template and inline the resulting render function
  83. * directly inside setup().
  84. * - Only affects `<script setup>`
  85. * - This should only be used in production because it prevents the template
  86. * from being hot-reloaded separately from component state.
  87. */
  88. inlineTemplate?: boolean
  89. /**
  90. * Generate the final component as a variable instead of default export.
  91. * This is useful in e.g. @vitejs/plugin-vue where the script needs to be
  92. * placed inside the main module.
  93. */
  94. genDefaultAs?: string
  95. /**
  96. * Options for template compilation when inlining. Note these are options that
  97. * would normally be passed to `compiler-sfc`'s own `compileTemplate()`, not
  98. * options passed to `compiler-dom`.
  99. */
  100. templateOptions?: Partial<SFCTemplateCompileOptions>
  101. /**
  102. * Hoist <script setup> static constants.
  103. * - Only enables when one `<script setup>` exists.
  104. * @default true
  105. */
  106. hoistStatic?: boolean
  107. /**
  108. * Set to `false` to disable reactive destructure for `defineProps` (pre-3.5
  109. * behavior), or set to `'error'` to throw hard error on props destructures.
  110. * @default true
  111. */
  112. propsDestructure?: boolean | 'error'
  113. /**
  114. * File system access methods to be used when resolving types
  115. * imported in SFC macros. Defaults to ts.sys in Node.js, can be overwritten
  116. * to use a virtual file system for use in browsers (e.g. in REPLs)
  117. */
  118. fs?: {
  119. fileExists(file: string): boolean
  120. readFile(file: string): string | undefined
  121. realpath?(file: string): string
  122. }
  123. /**
  124. * Transform Vue SFCs into custom elements.
  125. */
  126. customElement?: boolean | ((filename: string) => boolean)
  127. }
  128. export interface ImportBinding {
  129. isType: boolean
  130. imported: string
  131. local: string
  132. source: string
  133. isFromSetup: boolean
  134. isUsedInTemplate: boolean
  135. }
  136. const MACROS = [
  137. DEFINE_PROPS,
  138. DEFINE_EMITS,
  139. DEFINE_EXPOSE,
  140. DEFINE_OPTIONS,
  141. DEFINE_SLOTS,
  142. DEFINE_MODEL,
  143. WITH_DEFAULTS,
  144. ]
  145. /**
  146. * Compile `<script setup>`
  147. * It requires the whole SFC descriptor because we need to handle and merge
  148. * normal `<script>` + `<script setup>` if both are present.
  149. */
  150. export function compileScript(
  151. sfc: SFCDescriptor,
  152. options: SFCScriptCompileOptions,
  153. ): SFCScriptBlock {
  154. if (!options.id) {
  155. warnOnce(
  156. `compileScript now requires passing the \`id\` option.\n` +
  157. `Upgrade your vite or vue-loader version for compatibility with ` +
  158. `the latest experimental proposals.`,
  159. )
  160. }
  161. const ctx = new ScriptCompileContext(sfc, options)
  162. const { script, scriptSetup, source, filename } = sfc
  163. const hoistStatic = options.hoistStatic !== false && !script
  164. const scopeId = options.id ? options.id.replace(/^data-v-/, '') : ''
  165. const scriptLang = script && script.lang
  166. const scriptSetupLang = scriptSetup && scriptSetup.lang
  167. let refBindings: string[] | undefined
  168. if (!scriptSetup) {
  169. if (!script) {
  170. throw new Error(`[@vue/compiler-sfc] SFC contains no <script> tags.`)
  171. }
  172. // normal <script> only
  173. return processNormalScript(ctx, scopeId)
  174. }
  175. if (script && scriptLang !== scriptSetupLang) {
  176. throw new Error(
  177. `[@vue/compiler-sfc] <script> and <script setup> must have the same ` +
  178. `language type.`,
  179. )
  180. }
  181. if (scriptSetupLang && !ctx.isJS && !ctx.isTS) {
  182. // do not process non js/ts script blocks
  183. return scriptSetup
  184. }
  185. // metadata that needs to be returned
  186. // const ctx.bindingMetadata: BindingMetadata = {}
  187. const scriptBindings: Record<string, BindingTypes> = Object.create(null)
  188. const setupBindings: Record<string, BindingTypes> = Object.create(null)
  189. let defaultExport: Node | undefined
  190. let hasAwait = false
  191. let hasInlinedSsrRenderFn = false
  192. // string offsets
  193. const startOffset = ctx.startOffset!
  194. const endOffset = ctx.endOffset!
  195. const scriptStartOffset = script && script.loc.start.offset
  196. const scriptEndOffset = script && script.loc.end.offset
  197. function hoistNode(node: Statement) {
  198. const start = node.start! + startOffset
  199. let end = node.end! + startOffset
  200. // locate comment
  201. if (node.trailingComments && node.trailingComments.length > 0) {
  202. const lastCommentNode =
  203. node.trailingComments[node.trailingComments.length - 1]
  204. end = lastCommentNode.end! + startOffset
  205. }
  206. // locate the end of whitespace between this statement and the next
  207. while (end <= source.length) {
  208. if (!/\s/.test(source.charAt(end))) {
  209. break
  210. }
  211. end++
  212. }
  213. ctx.s.move(start, end, 0)
  214. }
  215. function registerUserImport(
  216. source: string,
  217. local: string,
  218. imported: string,
  219. isType: boolean,
  220. isFromSetup: boolean,
  221. needTemplateUsageCheck: boolean,
  222. ) {
  223. // template usage check is only needed in non-inline mode, so we can skip
  224. // the work if inlineTemplate is true.
  225. let isUsedInTemplate = needTemplateUsageCheck
  226. if (
  227. needTemplateUsageCheck &&
  228. ctx.isTS &&
  229. sfc.template &&
  230. !sfc.template.src &&
  231. !sfc.template.lang
  232. ) {
  233. isUsedInTemplate = isImportUsed(local, sfc)
  234. }
  235. ctx.userImports[local] = {
  236. isType,
  237. imported,
  238. local,
  239. source,
  240. isFromSetup,
  241. isUsedInTemplate,
  242. }
  243. }
  244. function checkInvalidScopeReference(node: Node | undefined, method: string) {
  245. if (!node) return
  246. walkIdentifiers(node, id => {
  247. const binding = setupBindings[id.name]
  248. if (binding && binding !== BindingTypes.LITERAL_CONST) {
  249. ctx.error(
  250. `\`${method}()\` in <script setup> cannot reference locally ` +
  251. `declared variables because it will be hoisted outside of the ` +
  252. `setup() function. If your component options require initialization ` +
  253. `in the module scope, use a separate normal <script> to export ` +
  254. `the options instead.`,
  255. id,
  256. )
  257. }
  258. })
  259. }
  260. const scriptAst = ctx.scriptAst
  261. const scriptSetupAst = ctx.scriptSetupAst!
  262. // 1.1 walk import declarations of <script>
  263. if (scriptAst) {
  264. for (const node of scriptAst.body) {
  265. if (node.type === 'ImportDeclaration') {
  266. // record imports for dedupe
  267. for (const specifier of node.specifiers) {
  268. const imported = getImportedName(specifier)
  269. registerUserImport(
  270. node.source.value,
  271. specifier.local.name,
  272. imported,
  273. node.importKind === 'type' ||
  274. (specifier.type === 'ImportSpecifier' &&
  275. specifier.importKind === 'type'),
  276. false,
  277. !options.inlineTemplate,
  278. )
  279. }
  280. }
  281. }
  282. }
  283. // 1.2 walk import declarations of <script setup>
  284. for (const node of scriptSetupAst.body) {
  285. if (node.type === 'ImportDeclaration') {
  286. // import declarations are moved to top
  287. hoistNode(node)
  288. // dedupe imports
  289. let removed = 0
  290. const removeSpecifier = (i: number) => {
  291. const removeLeft = i > removed
  292. removed++
  293. const current = node.specifiers[i]
  294. const next = node.specifiers[i + 1]
  295. ctx.s.remove(
  296. removeLeft
  297. ? node.specifiers[i - 1].end! + startOffset
  298. : current.start! + startOffset,
  299. next && !removeLeft
  300. ? next.start! + startOffset
  301. : current.end! + startOffset,
  302. )
  303. }
  304. for (let i = 0; i < node.specifiers.length; i++) {
  305. const specifier = node.specifiers[i]
  306. const local = specifier.local.name
  307. const imported = getImportedName(specifier)
  308. const source = node.source.value
  309. const existing = ctx.userImports[local]
  310. if (source === 'vue' && MACROS.includes(imported)) {
  311. if (local === imported) {
  312. warnOnce(
  313. `\`${imported}\` is a compiler macro and no longer needs to be imported.`,
  314. )
  315. } else {
  316. ctx.error(
  317. `\`${imported}\` is a compiler macro and cannot be aliased to ` +
  318. `a different name.`,
  319. specifier,
  320. )
  321. }
  322. removeSpecifier(i)
  323. } else if (existing) {
  324. if (existing.source === source && existing.imported === imported) {
  325. // already imported in <script setup>, dedupe
  326. removeSpecifier(i)
  327. } else {
  328. ctx.error(
  329. `different imports aliased to same local name.`,
  330. specifier,
  331. )
  332. }
  333. } else {
  334. registerUserImport(
  335. source,
  336. local,
  337. imported,
  338. node.importKind === 'type' ||
  339. (specifier.type === 'ImportSpecifier' &&
  340. specifier.importKind === 'type'),
  341. true,
  342. !options.inlineTemplate,
  343. )
  344. }
  345. }
  346. if (node.specifiers.length && removed === node.specifiers.length) {
  347. ctx.s.remove(node.start! + startOffset, node.end! + startOffset)
  348. }
  349. }
  350. }
  351. // 1.3 resolve possible user import alias of `ref` and `reactive`
  352. const vueImportAliases: Record<string, string> = {}
  353. for (const key in ctx.userImports) {
  354. const { source, imported, local } = ctx.userImports[key]
  355. if (source === 'vue') vueImportAliases[imported] = local
  356. }
  357. // 2.1 process normal <script> body
  358. if (script && scriptAst) {
  359. for (const node of scriptAst.body) {
  360. if (node.type === 'ExportDefaultDeclaration') {
  361. // export default
  362. defaultExport = node
  363. // check if user has manually specified `name` or 'render` option in
  364. // export default
  365. // if has name, skip name inference
  366. // if has render and no template, generate return object instead of
  367. // empty render function (#4980)
  368. let optionProperties
  369. if (defaultExport.declaration.type === 'ObjectExpression') {
  370. optionProperties = defaultExport.declaration.properties
  371. } else if (
  372. defaultExport.declaration.type === 'CallExpression' &&
  373. defaultExport.declaration.arguments[0] &&
  374. defaultExport.declaration.arguments[0].type === 'ObjectExpression'
  375. ) {
  376. optionProperties = defaultExport.declaration.arguments[0].properties
  377. }
  378. if (optionProperties) {
  379. for (const p of optionProperties) {
  380. if (
  381. p.type === 'ObjectProperty' &&
  382. p.key.type === 'Identifier' &&
  383. p.key.name === 'name'
  384. ) {
  385. ctx.hasDefaultExportName = true
  386. }
  387. if (
  388. (p.type === 'ObjectMethod' || p.type === 'ObjectProperty') &&
  389. p.key.type === 'Identifier' &&
  390. p.key.name === 'render'
  391. ) {
  392. // TODO warn when we provide a better way to do it?
  393. ctx.hasDefaultExportRender = true
  394. }
  395. }
  396. }
  397. // export default { ... } --> const __default__ = { ... }
  398. const start = node.start! + scriptStartOffset!
  399. const end = node.declaration.start! + scriptStartOffset!
  400. ctx.s.overwrite(start, end, `const ${normalScriptDefaultVar} = `)
  401. } else if (node.type === 'ExportNamedDeclaration') {
  402. const defaultSpecifier = node.specifiers.find(
  403. s =>
  404. s.exported.type === 'Identifier' && s.exported.name === 'default',
  405. ) as ExportSpecifier
  406. if (defaultSpecifier) {
  407. defaultExport = node
  408. // 1. remove specifier
  409. if (node.specifiers.length > 1) {
  410. ctx.s.remove(
  411. defaultSpecifier.start! + scriptStartOffset!,
  412. defaultSpecifier.end! + scriptStartOffset!,
  413. )
  414. } else {
  415. ctx.s.remove(
  416. node.start! + scriptStartOffset!,
  417. node.end! + scriptStartOffset!,
  418. )
  419. }
  420. if (node.source) {
  421. // export { x as default } from './x'
  422. // rewrite to `import { x as __default__ } from './x'` and
  423. // add to top
  424. ctx.s.prepend(
  425. `import { ${defaultSpecifier.local.name} as ${normalScriptDefaultVar} } from '${node.source.value}'\n`,
  426. )
  427. } else {
  428. // export { x as default }
  429. // rewrite to `const __default__ = x` and move to end
  430. ctx.s.appendLeft(
  431. scriptEndOffset!,
  432. `\nconst ${normalScriptDefaultVar} = ${defaultSpecifier.local.name}\n`,
  433. )
  434. }
  435. }
  436. if (node.declaration) {
  437. walkDeclaration(
  438. 'script',
  439. node.declaration,
  440. scriptBindings,
  441. vueImportAliases,
  442. hoistStatic,
  443. )
  444. }
  445. } else if (
  446. (node.type === 'VariableDeclaration' ||
  447. node.type === 'FunctionDeclaration' ||
  448. node.type === 'ClassDeclaration' ||
  449. node.type === 'TSEnumDeclaration') &&
  450. !node.declare
  451. ) {
  452. walkDeclaration(
  453. 'script',
  454. node,
  455. scriptBindings,
  456. vueImportAliases,
  457. hoistStatic,
  458. )
  459. }
  460. }
  461. // <script> after <script setup>
  462. // we need to move the block up so that `const __default__` is
  463. // declared before being used in the actual component definition
  464. if (scriptStartOffset! > startOffset) {
  465. // if content doesn't end with newline, add one
  466. if (!/\n$/.test(script.content.trim())) {
  467. ctx.s.appendLeft(scriptEndOffset!, `\n`)
  468. }
  469. ctx.s.move(scriptStartOffset!, scriptEndOffset!, 0)
  470. }
  471. }
  472. // 2.2 process <script setup> body
  473. for (const node of scriptSetupAst.body) {
  474. if (node.type === 'ExpressionStatement') {
  475. const expr = unwrapTSNode(node.expression)
  476. // process `defineProps` and `defineEmit(s)` calls
  477. if (
  478. processDefineProps(ctx, expr) ||
  479. processDefineEmits(ctx, expr) ||
  480. processDefineOptions(ctx, expr) ||
  481. processDefineSlots(ctx, expr)
  482. ) {
  483. ctx.s.remove(node.start! + startOffset, node.end! + startOffset)
  484. } else if (processDefineExpose(ctx, expr)) {
  485. // defineExpose({}) -> expose({})
  486. const callee = (expr as CallExpression).callee
  487. ctx.s.overwrite(
  488. callee.start! + startOffset,
  489. callee.end! + startOffset,
  490. '__expose',
  491. )
  492. } else {
  493. processDefineModel(ctx, expr)
  494. }
  495. }
  496. if (node.type === 'VariableDeclaration' && !node.declare) {
  497. const total = node.declarations.length
  498. let left = total
  499. let lastNonRemoved: number | undefined
  500. for (let i = 0; i < total; i++) {
  501. const decl = node.declarations[i]
  502. const init = decl.init && unwrapTSNode(decl.init)
  503. if (init) {
  504. if (processDefineOptions(ctx, init)) {
  505. ctx.error(
  506. `${DEFINE_OPTIONS}() has no returning value, it cannot be assigned.`,
  507. node,
  508. )
  509. }
  510. // defineProps
  511. const isDefineProps = processDefineProps(ctx, init, decl.id)
  512. if (ctx.propsDestructureRestId) {
  513. setupBindings[ctx.propsDestructureRestId] =
  514. BindingTypes.SETUP_REACTIVE_CONST
  515. }
  516. // defineEmits
  517. const isDefineEmits =
  518. !isDefineProps && processDefineEmits(ctx, init, decl.id)
  519. !isDefineEmits &&
  520. (processDefineSlots(ctx, init, decl.id) ||
  521. processDefineModel(ctx, init, decl.id))
  522. if (
  523. isDefineProps &&
  524. !ctx.propsDestructureRestId &&
  525. ctx.propsDestructureDecl
  526. ) {
  527. if (left === 1) {
  528. ctx.s.remove(node.start! + startOffset, node.end! + startOffset)
  529. } else {
  530. let start = decl.start! + startOffset
  531. let end = decl.end! + startOffset
  532. if (i === total - 1) {
  533. // last one, locate the end of the last one that is not removed
  534. // if we arrive at this branch, there must have been a
  535. // non-removed decl before us, so lastNonRemoved is non-null.
  536. start = node.declarations[lastNonRemoved!].end! + startOffset
  537. } else {
  538. // not the last one, locate the start of the next
  539. end = node.declarations[i + 1].start! + startOffset
  540. }
  541. ctx.s.remove(start, end)
  542. left--
  543. }
  544. } else if (isDefineEmits) {
  545. ctx.s.overwrite(
  546. startOffset + init.start!,
  547. startOffset + init.end!,
  548. '__emit',
  549. )
  550. } else {
  551. lastNonRemoved = i
  552. }
  553. }
  554. }
  555. }
  556. let isAllLiteral = false
  557. // walk declarations to record declared bindings
  558. if (
  559. (node.type === 'VariableDeclaration' ||
  560. node.type === 'FunctionDeclaration' ||
  561. node.type === 'ClassDeclaration' ||
  562. node.type === 'TSEnumDeclaration') &&
  563. !node.declare
  564. ) {
  565. isAllLiteral = walkDeclaration(
  566. 'scriptSetup',
  567. node,
  568. setupBindings,
  569. vueImportAliases,
  570. hoistStatic,
  571. !!ctx.propsDestructureDecl,
  572. )
  573. }
  574. // hoist literal constants
  575. if (hoistStatic && isAllLiteral) {
  576. hoistNode(node)
  577. }
  578. // walk statements & named exports / variable declarations for top level
  579. // await
  580. if (
  581. (node.type === 'VariableDeclaration' && !node.declare) ||
  582. node.type.endsWith('Statement')
  583. ) {
  584. const scope: Statement[][] = [scriptSetupAst.body]
  585. walk(node, {
  586. enter(child: Node, parent: Node | null) {
  587. if (isFunctionType(child)) {
  588. this.skip()
  589. }
  590. if (child.type === 'BlockStatement') {
  591. scope.push(child.body)
  592. }
  593. if (child.type === 'AwaitExpression') {
  594. hasAwait = true
  595. // if the await expression is an expression statement and
  596. // - is in the root scope
  597. // - or is not the first statement in a nested block scope
  598. // then it needs a semicolon before the generated code.
  599. const currentScope = scope[scope.length - 1]
  600. const needsSemi = currentScope.some((n, i) => {
  601. return (
  602. (scope.length === 1 || i > 0) &&
  603. n.type === 'ExpressionStatement' &&
  604. n.start === child.start
  605. )
  606. })
  607. processAwait(
  608. ctx,
  609. child,
  610. needsSemi,
  611. parent!.type === 'ExpressionStatement',
  612. )
  613. }
  614. },
  615. exit(node: Node) {
  616. if (node.type === 'BlockStatement') scope.pop()
  617. },
  618. })
  619. }
  620. if (
  621. (node.type === 'ExportNamedDeclaration' && node.exportKind !== 'type') ||
  622. node.type === 'ExportAllDeclaration' ||
  623. node.type === 'ExportDefaultDeclaration'
  624. ) {
  625. ctx.error(
  626. `<script setup> cannot contain ES module exports. ` +
  627. `If you are using a previous version of <script setup>, please ` +
  628. `consult the updated RFC at https://github.com/vuejs/rfcs/pull/227.`,
  629. node,
  630. )
  631. }
  632. if (ctx.isTS) {
  633. // move all Type declarations to outer scope
  634. if (
  635. node.type.startsWith('TS') ||
  636. (node.type === 'ExportNamedDeclaration' &&
  637. node.exportKind === 'type') ||
  638. (node.type === 'VariableDeclaration' && node.declare)
  639. ) {
  640. if (node.type !== 'TSEnumDeclaration') {
  641. hoistNode(node)
  642. }
  643. }
  644. }
  645. }
  646. // 3 props destructure transform
  647. if (ctx.propsDestructureDecl) {
  648. transformDestructuredProps(ctx, vueImportAliases)
  649. }
  650. // 4. check macro args to make sure it doesn't reference setup scope
  651. // variables
  652. checkInvalidScopeReference(ctx.propsRuntimeDecl, DEFINE_PROPS)
  653. checkInvalidScopeReference(ctx.propsRuntimeDefaults, DEFINE_PROPS)
  654. checkInvalidScopeReference(ctx.propsDestructureDecl, DEFINE_PROPS)
  655. checkInvalidScopeReference(ctx.emitsRuntimeDecl, DEFINE_EMITS)
  656. checkInvalidScopeReference(ctx.optionsRuntimeDecl, DEFINE_OPTIONS)
  657. for (const { runtimeOptionNodes } of Object.values(ctx.modelDecls)) {
  658. for (const node of runtimeOptionNodes) {
  659. checkInvalidScopeReference(node, DEFINE_MODEL)
  660. }
  661. }
  662. // 5. remove non-script content
  663. if (script) {
  664. if (startOffset < scriptStartOffset!) {
  665. // <script setup> before <script>
  666. ctx.s.remove(0, startOffset)
  667. ctx.s.remove(endOffset, scriptStartOffset!)
  668. ctx.s.remove(scriptEndOffset!, source.length)
  669. } else {
  670. // <script> before <script setup>
  671. ctx.s.remove(0, scriptStartOffset!)
  672. ctx.s.remove(scriptEndOffset!, startOffset)
  673. ctx.s.remove(endOffset, source.length)
  674. }
  675. } else {
  676. // only <script setup>
  677. ctx.s.remove(0, startOffset)
  678. ctx.s.remove(endOffset, source.length)
  679. }
  680. // 6. analyze binding metadata
  681. // `defineProps` & `defineModel` also register props bindings
  682. if (scriptAst) {
  683. Object.assign(ctx.bindingMetadata, analyzeScriptBindings(scriptAst.body))
  684. }
  685. for (const [key, { isType, imported, source }] of Object.entries(
  686. ctx.userImports,
  687. )) {
  688. if (isType) continue
  689. ctx.bindingMetadata[key] =
  690. imported === '*' ||
  691. (imported === 'default' && source.endsWith('.vue')) ||
  692. source === 'vue'
  693. ? BindingTypes.SETUP_CONST
  694. : BindingTypes.SETUP_MAYBE_REF
  695. }
  696. for (const key in scriptBindings) {
  697. ctx.bindingMetadata[key] = scriptBindings[key]
  698. }
  699. for (const key in setupBindings) {
  700. ctx.bindingMetadata[key] = setupBindings[key]
  701. }
  702. // known ref bindings
  703. if (refBindings) {
  704. for (const key of refBindings) {
  705. ctx.bindingMetadata[key] = BindingTypes.SETUP_REF
  706. }
  707. }
  708. // 7. inject `useCssVars` calls
  709. if (
  710. sfc.cssVars.length &&
  711. // no need to do this when targeting SSR
  712. !options.templateOptions?.ssr
  713. ) {
  714. ctx.helperImports.add(CSS_VARS_HELPER)
  715. ctx.helperImports.add('unref')
  716. ctx.s.prependLeft(
  717. startOffset,
  718. `\n${genCssVarsCode(
  719. sfc.cssVars,
  720. ctx.bindingMetadata,
  721. scopeId,
  722. !!options.isProd,
  723. )}\n`,
  724. )
  725. }
  726. // 8. finalize setup() argument signature
  727. let args = `__props`
  728. if (ctx.propsTypeDecl) {
  729. // mark as any and only cast on assignment
  730. // since the user defined complex types may be incompatible with the
  731. // inferred type from generated runtime declarations
  732. args += `: any`
  733. }
  734. // inject user assignment of props
  735. // we use a default __props so that template expressions referencing props
  736. // can use it directly
  737. if (ctx.propsDecl) {
  738. if (ctx.propsDestructureRestId) {
  739. ctx.s.overwrite(
  740. startOffset + ctx.propsCall!.start!,
  741. startOffset + ctx.propsCall!.end!,
  742. `${ctx.helper(`createPropsRestProxy`)}(__props, ${JSON.stringify(
  743. Object.keys(ctx.propsDestructuredBindings),
  744. )})`,
  745. )
  746. ctx.s.overwrite(
  747. startOffset + ctx.propsDestructureDecl!.start!,
  748. startOffset + ctx.propsDestructureDecl!.end!,
  749. ctx.propsDestructureRestId,
  750. )
  751. } else if (!ctx.propsDestructureDecl) {
  752. ctx.s.overwrite(
  753. startOffset + ctx.propsCall!.start!,
  754. startOffset + ctx.propsCall!.end!,
  755. '__props',
  756. )
  757. }
  758. }
  759. // inject temp variables for async context preservation
  760. if (hasAwait) {
  761. const any = ctx.isTS ? `: any` : ``
  762. ctx.s.prependLeft(startOffset, `\nlet __temp${any}, __restore${any}\n`)
  763. }
  764. const destructureElements =
  765. ctx.hasDefineExposeCall || !options.inlineTemplate
  766. ? [`expose: __expose`]
  767. : []
  768. if (ctx.emitDecl) {
  769. destructureElements.push(`emit: __emit`)
  770. }
  771. if (destructureElements.length) {
  772. args += `, { ${destructureElements.join(', ')} }`
  773. }
  774. // 9. generate return statement
  775. let returned
  776. if (
  777. !options.inlineTemplate ||
  778. (!sfc.template && ctx.hasDefaultExportRender)
  779. ) {
  780. // non-inline mode, or has manual render in normal <script>
  781. // return bindings from script and script setup
  782. const allBindings: Record<string, any> = {
  783. ...scriptBindings,
  784. ...setupBindings,
  785. }
  786. for (const key in ctx.userImports) {
  787. if (
  788. !ctx.userImports[key].isType &&
  789. ctx.userImports[key].isUsedInTemplate
  790. ) {
  791. allBindings[key] = true
  792. }
  793. }
  794. returned = `{ `
  795. for (const key in allBindings) {
  796. if (
  797. allBindings[key] === true &&
  798. ctx.userImports[key].source !== 'vue' &&
  799. !ctx.userImports[key].source.endsWith('.vue')
  800. ) {
  801. // generate getter for import bindings
  802. // skip vue imports since we know they will never change
  803. returned += `get ${key}() { return ${key} }, `
  804. } else if (ctx.bindingMetadata[key] === BindingTypes.SETUP_LET) {
  805. // local let binding, also add setter
  806. const setArg = key === 'v' ? `_v` : `v`
  807. returned +=
  808. `get ${key}() { return ${key} }, ` +
  809. `set ${key}(${setArg}) { ${key} = ${setArg} }, `
  810. } else {
  811. returned += `${key}, `
  812. }
  813. }
  814. returned = returned.replace(/, $/, '') + ` }`
  815. } else {
  816. // inline mode
  817. if (sfc.template && !sfc.template.src) {
  818. if (options.templateOptions && options.templateOptions.ssr) {
  819. hasInlinedSsrRenderFn = true
  820. }
  821. // inline render function mode - we are going to compile the template and
  822. // inline it right here
  823. const { code, ast, preamble, tips, errors } = compileTemplate({
  824. filename,
  825. ast: sfc.template.ast,
  826. source: sfc.template.content,
  827. inMap: sfc.template.map,
  828. ...options.templateOptions,
  829. id: scopeId,
  830. scoped: sfc.styles.some(s => s.scoped),
  831. isProd: options.isProd,
  832. ssrCssVars: sfc.cssVars,
  833. compilerOptions: {
  834. ...(options.templateOptions &&
  835. options.templateOptions.compilerOptions),
  836. inline: true,
  837. isTS: ctx.isTS,
  838. bindingMetadata: ctx.bindingMetadata,
  839. },
  840. })
  841. if (tips.length) {
  842. tips.forEach(warnOnce)
  843. }
  844. const err = errors[0]
  845. if (typeof err === 'string') {
  846. throw new Error(err)
  847. } else if (err) {
  848. if (err.loc) {
  849. err.message +=
  850. `\n\n` +
  851. sfc.filename +
  852. '\n' +
  853. generateCodeFrame(
  854. source,
  855. err.loc.start.offset,
  856. err.loc.end.offset,
  857. ) +
  858. `\n`
  859. }
  860. throw err
  861. }
  862. if (preamble) {
  863. ctx.s.prepend(preamble)
  864. }
  865. // avoid duplicated unref import
  866. // as this may get injected by the render function preamble OR the
  867. // css vars codegen
  868. if (ast && ast.helpers.has(UNREF)) {
  869. ctx.helperImports.delete('unref')
  870. }
  871. returned = code
  872. } else {
  873. returned = `() => {}`
  874. }
  875. }
  876. if (!options.inlineTemplate && !__TEST__) {
  877. // in non-inline mode, the `__isScriptSetup: true` flag is used by
  878. // componentPublicInstance proxy to allow properties that start with $ or _
  879. ctx.s.appendRight(
  880. endOffset,
  881. `\nconst __returned__ = ${returned}\n` +
  882. `Object.defineProperty(__returned__, '__isScriptSetup', { enumerable: false, value: true })\n` +
  883. `return __returned__` +
  884. `\n}\n\n`,
  885. )
  886. } else {
  887. ctx.s.appendRight(endOffset, `\nreturn ${returned}\n}\n\n`)
  888. }
  889. // 10. finalize default export
  890. const genDefaultAs = options.genDefaultAs
  891. ? `const ${options.genDefaultAs} =`
  892. : `export default`
  893. let runtimeOptions = ``
  894. if (!ctx.hasDefaultExportName && filename && filename !== DEFAULT_FILENAME) {
  895. const match = filename.match(/([^/\\]+)\.\w+$/)
  896. if (match) {
  897. runtimeOptions += `\n __name: '${match[1]}',`
  898. }
  899. }
  900. if (hasInlinedSsrRenderFn) {
  901. runtimeOptions += `\n __ssrInlineRender: true,`
  902. }
  903. const propsDecl = genRuntimeProps(ctx)
  904. if (propsDecl) runtimeOptions += `\n props: ${propsDecl},`
  905. const emitsDecl = genRuntimeEmits(ctx)
  906. if (emitsDecl) runtimeOptions += `\n emits: ${emitsDecl},`
  907. let definedOptions = ''
  908. if (ctx.optionsRuntimeDecl) {
  909. definedOptions = scriptSetup.content
  910. .slice(ctx.optionsRuntimeDecl.start!, ctx.optionsRuntimeDecl.end!)
  911. .trim()
  912. }
  913. // <script setup> components are closed by default. If the user did not
  914. // explicitly call `defineExpose`, call expose() with no args.
  915. const exposeCall =
  916. ctx.hasDefineExposeCall || options.inlineTemplate ? `` : ` __expose();\n`
  917. // wrap setup code with function.
  918. if (ctx.isTS) {
  919. // for TS, make sure the exported type is still valid type with
  920. // correct props information
  921. // we have to use object spread for types to be merged properly
  922. // user's TS setting should compile it down to proper targets
  923. // export default defineComponent({ ...__default__, ... })
  924. const def =
  925. (defaultExport ? `\n ...${normalScriptDefaultVar},` : ``) +
  926. (definedOptions ? `\n ...${definedOptions},` : '')
  927. ctx.s.prependLeft(
  928. startOffset,
  929. `\n${genDefaultAs} /*@__PURE__*/${ctx.helper(
  930. `defineComponent`,
  931. )}({${def}${runtimeOptions}\n ${
  932. hasAwait ? `async ` : ``
  933. }setup(${args}) {\n${exposeCall}`,
  934. )
  935. ctx.s.appendRight(endOffset, `})`)
  936. } else {
  937. if (defaultExport || definedOptions) {
  938. // without TS, can't rely on rest spread, so we use Object.assign
  939. // export default Object.assign(__default__, { ... })
  940. ctx.s.prependLeft(
  941. startOffset,
  942. `\n${genDefaultAs} /*@__PURE__*/Object.assign(${
  943. defaultExport ? `${normalScriptDefaultVar}, ` : ''
  944. }${definedOptions ? `${definedOptions}, ` : ''}{${runtimeOptions}\n ` +
  945. `${hasAwait ? `async ` : ``}setup(${args}) {\n${exposeCall}`,
  946. )
  947. ctx.s.appendRight(endOffset, `})`)
  948. } else {
  949. ctx.s.prependLeft(
  950. startOffset,
  951. `\n${genDefaultAs} {${runtimeOptions}\n ` +
  952. `${hasAwait ? `async ` : ``}setup(${args}) {\n${exposeCall}`,
  953. )
  954. ctx.s.appendRight(endOffset, `}`)
  955. }
  956. }
  957. // 11. finalize Vue helper imports
  958. if (ctx.helperImports.size > 0) {
  959. const runtimeModuleName =
  960. options.templateOptions?.compilerOptions?.runtimeModuleName
  961. const importSrc = runtimeModuleName
  962. ? JSON.stringify(runtimeModuleName)
  963. : `'vue'`
  964. ctx.s.prepend(
  965. `import { ${[...ctx.helperImports]
  966. .map(h => `${h} as _${h}`)
  967. .join(', ')} } from ${importSrc}\n`,
  968. )
  969. }
  970. return {
  971. ...scriptSetup,
  972. bindings: ctx.bindingMetadata,
  973. imports: ctx.userImports,
  974. content: ctx.s.toString(),
  975. map:
  976. options.sourceMap !== false
  977. ? (ctx.s.generateMap({
  978. source: filename,
  979. hires: true,
  980. includeContent: true,
  981. }) as unknown as RawSourceMap)
  982. : undefined,
  983. scriptAst: scriptAst?.body,
  984. scriptSetupAst: scriptSetupAst?.body,
  985. deps: ctx.deps ? [...ctx.deps] : undefined,
  986. }
  987. }
  988. function registerBinding(
  989. bindings: Record<string, BindingTypes>,
  990. node: Identifier,
  991. type: BindingTypes,
  992. ) {
  993. bindings[node.name] = type
  994. }
  995. function walkDeclaration(
  996. from: 'script' | 'scriptSetup',
  997. node: Declaration,
  998. bindings: Record<string, BindingTypes>,
  999. userImportAliases: Record<string, string>,
  1000. hoistStatic: boolean,
  1001. isPropsDestructureEnabled = false,
  1002. ): boolean {
  1003. let isAllLiteral = false
  1004. if (node.type === 'VariableDeclaration') {
  1005. const isConst = node.kind === 'const'
  1006. isAllLiteral =
  1007. isConst &&
  1008. node.declarations.every(
  1009. decl => decl.id.type === 'Identifier' && isStaticNode(decl.init!),
  1010. )
  1011. // export const foo = ...
  1012. for (const { id, init: _init } of node.declarations) {
  1013. const init = _init && unwrapTSNode(_init)
  1014. const isConstMacroCall =
  1015. isConst &&
  1016. isCallOf(
  1017. init,
  1018. c =>
  1019. c === DEFINE_PROPS ||
  1020. c === DEFINE_EMITS ||
  1021. c === WITH_DEFAULTS ||
  1022. c === DEFINE_SLOTS,
  1023. )
  1024. if (id.type === 'Identifier') {
  1025. let bindingType
  1026. const userReactiveBinding = userImportAliases['reactive']
  1027. if (
  1028. (hoistStatic || from === 'script') &&
  1029. (isAllLiteral || (isConst && isStaticNode(init!)))
  1030. ) {
  1031. bindingType = BindingTypes.LITERAL_CONST
  1032. } else if (isCallOf(init, userReactiveBinding)) {
  1033. // treat reactive() calls as let since it's meant to be mutable
  1034. bindingType = isConst
  1035. ? BindingTypes.SETUP_REACTIVE_CONST
  1036. : BindingTypes.SETUP_LET
  1037. } else if (
  1038. // if a declaration is a const literal, we can mark it so that
  1039. // the generated render fn code doesn't need to unref() it
  1040. isConstMacroCall ||
  1041. (isConst && canNeverBeRef(init!, userReactiveBinding))
  1042. ) {
  1043. bindingType = isCallOf(init, DEFINE_PROPS)
  1044. ? BindingTypes.SETUP_REACTIVE_CONST
  1045. : BindingTypes.SETUP_CONST
  1046. } else if (isConst) {
  1047. if (
  1048. isCallOf(
  1049. init,
  1050. m =>
  1051. m === userImportAliases['ref'] ||
  1052. m === userImportAliases['computed'] ||
  1053. m === userImportAliases['shallowRef'] ||
  1054. m === userImportAliases['customRef'] ||
  1055. m === userImportAliases['toRef'] ||
  1056. m === DEFINE_MODEL,
  1057. )
  1058. ) {
  1059. bindingType = BindingTypes.SETUP_REF
  1060. } else {
  1061. bindingType = BindingTypes.SETUP_MAYBE_REF
  1062. }
  1063. } else {
  1064. bindingType = BindingTypes.SETUP_LET
  1065. }
  1066. registerBinding(bindings, id, bindingType)
  1067. } else {
  1068. if (isCallOf(init, DEFINE_PROPS) && isPropsDestructureEnabled) {
  1069. continue
  1070. }
  1071. if (id.type === 'ObjectPattern') {
  1072. walkObjectPattern(id, bindings, isConst, isConstMacroCall)
  1073. } else if (id.type === 'ArrayPattern') {
  1074. walkArrayPattern(id, bindings, isConst, isConstMacroCall)
  1075. }
  1076. }
  1077. }
  1078. } else if (node.type === 'TSEnumDeclaration') {
  1079. isAllLiteral = node.members.every(
  1080. member => !member.initializer || isStaticNode(member.initializer),
  1081. )
  1082. bindings[node.id!.name] = isAllLiteral
  1083. ? BindingTypes.LITERAL_CONST
  1084. : BindingTypes.SETUP_CONST
  1085. } else if (
  1086. node.type === 'FunctionDeclaration' ||
  1087. node.type === 'ClassDeclaration'
  1088. ) {
  1089. // export function foo() {} / export class Foo {}
  1090. // export declarations must be named.
  1091. bindings[node.id!.name] = BindingTypes.SETUP_CONST
  1092. }
  1093. return isAllLiteral
  1094. }
  1095. function walkObjectPattern(
  1096. node: ObjectPattern,
  1097. bindings: Record<string, BindingTypes>,
  1098. isConst: boolean,
  1099. isDefineCall = false,
  1100. ) {
  1101. for (const p of node.properties) {
  1102. if (p.type === 'ObjectProperty') {
  1103. if (p.key.type === 'Identifier' && p.key === p.value) {
  1104. // shorthand: const { x } = ...
  1105. const type = isDefineCall
  1106. ? BindingTypes.SETUP_CONST
  1107. : isConst
  1108. ? BindingTypes.SETUP_MAYBE_REF
  1109. : BindingTypes.SETUP_LET
  1110. registerBinding(bindings, p.key, type)
  1111. } else {
  1112. walkPattern(p.value, bindings, isConst, isDefineCall)
  1113. }
  1114. } else {
  1115. // ...rest
  1116. // argument can only be identifier when destructuring
  1117. const type = isConst ? BindingTypes.SETUP_CONST : BindingTypes.SETUP_LET
  1118. registerBinding(bindings, p.argument as Identifier, type)
  1119. }
  1120. }
  1121. }
  1122. function walkArrayPattern(
  1123. node: ArrayPattern,
  1124. bindings: Record<string, BindingTypes>,
  1125. isConst: boolean,
  1126. isDefineCall = false,
  1127. ) {
  1128. for (const e of node.elements) {
  1129. e && walkPattern(e, bindings, isConst, isDefineCall)
  1130. }
  1131. }
  1132. function walkPattern(
  1133. node: Node,
  1134. bindings: Record<string, BindingTypes>,
  1135. isConst: boolean,
  1136. isDefineCall = false,
  1137. ) {
  1138. if (node.type === 'Identifier') {
  1139. const type = isDefineCall
  1140. ? BindingTypes.SETUP_CONST
  1141. : isConst
  1142. ? BindingTypes.SETUP_MAYBE_REF
  1143. : BindingTypes.SETUP_LET
  1144. registerBinding(bindings, node, type)
  1145. } else if (node.type === 'RestElement') {
  1146. // argument can only be identifier when destructuring
  1147. const type = isConst ? BindingTypes.SETUP_CONST : BindingTypes.SETUP_LET
  1148. registerBinding(bindings, node.argument as Identifier, type)
  1149. } else if (node.type === 'ObjectPattern') {
  1150. walkObjectPattern(node, bindings, isConst)
  1151. } else if (node.type === 'ArrayPattern') {
  1152. walkArrayPattern(node, bindings, isConst)
  1153. } else if (node.type === 'AssignmentPattern') {
  1154. if (node.left.type === 'Identifier') {
  1155. const type = isDefineCall
  1156. ? BindingTypes.SETUP_CONST
  1157. : isConst
  1158. ? BindingTypes.SETUP_MAYBE_REF
  1159. : BindingTypes.SETUP_LET
  1160. registerBinding(bindings, node.left, type)
  1161. } else {
  1162. walkPattern(node.left, bindings, isConst)
  1163. }
  1164. }
  1165. }
  1166. function canNeverBeRef(node: Node, userReactiveImport?: string): boolean {
  1167. if (isCallOf(node, userReactiveImport)) {
  1168. return true
  1169. }
  1170. switch (node.type) {
  1171. case 'UnaryExpression':
  1172. case 'BinaryExpression':
  1173. case 'ArrayExpression':
  1174. case 'ObjectExpression':
  1175. case 'FunctionExpression':
  1176. case 'ArrowFunctionExpression':
  1177. case 'UpdateExpression':
  1178. case 'ClassExpression':
  1179. case 'TaggedTemplateExpression':
  1180. return true
  1181. case 'SequenceExpression':
  1182. return canNeverBeRef(
  1183. node.expressions[node.expressions.length - 1],
  1184. userReactiveImport,
  1185. )
  1186. default:
  1187. if (isLiteralNode(node)) {
  1188. return true
  1189. }
  1190. return false
  1191. }
  1192. }
  1193. function isStaticNode(node: Node): boolean {
  1194. node = unwrapTSNode(node)
  1195. switch (node.type) {
  1196. case 'UnaryExpression': // void 0, !true
  1197. return isStaticNode(node.argument)
  1198. case 'LogicalExpression': // 1 > 2
  1199. case 'BinaryExpression': // 1 + 2
  1200. return isStaticNode(node.left) && isStaticNode(node.right)
  1201. case 'ConditionalExpression': {
  1202. // 1 ? 2 : 3
  1203. return (
  1204. isStaticNode(node.test) &&
  1205. isStaticNode(node.consequent) &&
  1206. isStaticNode(node.alternate)
  1207. )
  1208. }
  1209. case 'SequenceExpression': // (1, 2)
  1210. case 'TemplateLiteral': // `foo${1}`
  1211. return node.expressions.every(expr => isStaticNode(expr))
  1212. case 'ParenthesizedExpression': // (1)
  1213. return isStaticNode(node.expression)
  1214. case 'StringLiteral':
  1215. case 'NumericLiteral':
  1216. case 'BooleanLiteral':
  1217. case 'NullLiteral':
  1218. case 'BigIntLiteral':
  1219. return true
  1220. }
  1221. return false
  1222. }