]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat: add vapor errors of `v-bind` / `v-on` (#3)
authorRizumu Ayaka <rizumu@ayaka.moe>
Tue, 28 Nov 2023 10:17:41 +0000 (18:17 +0800)
committerGitHub <noreply@github.com>
Tue, 28 Nov 2023 10:17:41 +0000 (18:17 +0800)
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
packages/compiler-core/src/index.ts
packages/compiler-vapor/__tests__/compile.test.ts
packages/compiler-vapor/src/errors.ts [new file with mode: 0644]
packages/compiler-vapor/src/transform.ts

index 4898a181dfcfad8c42defd4d6929ef27a07a8577..8aaa0d77e28582b03ecd303c73630789877042ff 100644 (file)
@@ -25,6 +25,8 @@ export { generate, type CodegenContext, type CodegenResult } from './codegen'
 export {
   ErrorCodes,
   createCompilerError,
+  defaultOnError,
+  defaultOnWarn,
   type CoreCompilerError,
   type CompilerError
 } from './errors'
index ca355f2d29c44ced74782372a79ff8160df06484..e9766a806003c6a853747099e8bcb77deaa71450 100644 (file)
@@ -2,6 +2,7 @@ import { BindingTypes, CompilerOptions, RootNode } from '@vue/compiler-dom'
 // TODO remove it
 import { format } from 'prettier'
 import { compile as _compile } from '../src'
+import { ErrorCodes } from '../src/errors'
 
 async function compile(
   template: string | RootNode,
@@ -71,6 +72,25 @@ describe('compile', () => {
         })
         expect(code).matchSnapshot()
       })
+
+      test('should error if no expression', async () => {
+        const onError = vi.fn()
+        await compile(`<div v-bind:arg />`, { onError })
+
+        expect(onError.mock.calls[0][0]).toMatchObject({
+          code: ErrorCodes.VAPOR_BIND_NO_EXPRESSION,
+          loc: {
+            start: {
+              line: 1,
+              column: 6,
+            },
+            end: {
+              line: 1,
+              column: 16,
+            },
+          },
+        })
+      })
     })
 
     describe('v-on', () => {
@@ -82,6 +102,24 @@ describe('compile', () => {
         })
         expect(code).matchSnapshot()
       })
+
+      test('should error if no expression AND no modifier', async () => {
+        const onError = vi.fn()
+        await compile(`<div v-on:click />`, { onError })
+        expect(onError.mock.calls[0][0]).toMatchObject({
+          code: ErrorCodes.VAPOR_ON_NO_EXPRESSION,
+          loc: {
+            start: {
+              line: 1,
+              column: 6,
+            },
+            end: {
+              line: 1,
+              column: 16,
+            },
+          },
+        })
+      })
     })
 
     describe('v-html', () => {
diff --git a/packages/compiler-vapor/src/errors.ts b/packages/compiler-vapor/src/errors.ts
new file mode 100644 (file)
index 0000000..0f343e7
--- /dev/null
@@ -0,0 +1,19 @@
+export {
+  createCompilerError,
+  defaultOnError,
+  defaultOnWarn,
+  type CoreCompilerError,
+  type CompilerError,
+} from '@vue/compiler-dom'
+
+export const enum ErrorCodes {
+  // transform errors
+  VAPOR_BIND_NO_EXPRESSION,
+  VAPOR_ON_NO_EXPRESSION,
+}
+
+export const errorMessages: Record<ErrorCodes, string> = {
+  // transform errors
+  [ErrorCodes.VAPOR_BIND_NO_EXPRESSION]: `v-bind is missing expression.`,
+  [ErrorCodes.VAPOR_ON_NO_EXPRESSION]: `v-on is missing expression.`,
+}
index 67355cdf791153a8c6b73eebaf681949c364f10e..7d38676c810ac5e7060e5a7a6d749a00c0c17a8b 100644 (file)
@@ -1,14 +1,14 @@
-import type {
+import {
   NodeTypes,
-  RootNode,
-  Node,
-  TemplateChildNode,
-  ElementNode,
-  AttributeNode,
-  InterpolationNode,
-  TransformOptions,
-  DirectiveNode,
-  ExpressionNode,
+  type RootNode,
+  type Node,
+  type TemplateChildNode,
+  type ElementNode,
+  type AttributeNode,
+  type InterpolationNode,
+  type TransformOptions,
+  type DirectiveNode,
+  type ExpressionNode,
 } from '@vue/compiler-dom'
 import {
   type OperationNode,
@@ -17,6 +17,12 @@ import {
   DynamicInfo,
 } from './ir'
 import { isVoidTag } from '@vue/shared'
+import {
+  ErrorCodes,
+  createCompilerError,
+  defaultOnError,
+  defaultOnWarn,
+} from './errors'
 
 export interface TransformContext<T extends Node = Node> {
   node: T
@@ -129,6 +135,9 @@ export function transform(
   root: RootNode,
   options: TransformOptions = {},
 ): RootIRNode {
+  options.onError ||= defaultOnError
+  options.onWarn ||= defaultOnWarn
+
   const ir: RootIRNode = {
     type: IRNodeTypes.ROOT,
     loc: root.loc,
@@ -145,6 +154,7 @@ export function transform(
     helpers: new Set([]),
     vaporHelpers: new Set([]),
   }
+
   const ctx = createRootContext(ir, root, options)
 
   // TODO: transform presets, see packages/compiler-core/src/transforms
@@ -344,9 +354,21 @@ function transformProp(
     return
   }
 
-  const expr = processExpression(ctx, node.exp)
+  const { exp, loc, modifiers } = node
+
+  const expr = processExpression(ctx, exp)
   switch (name) {
     case 'bind': {
+      if (
+        !exp ||
+        (exp.type === NodeTypes.SIMPLE_EXPRESSION! && !exp.content.trim())
+      ) {
+        ctx.options.onError!(
+          createCompilerError(ErrorCodes.VAPOR_BIND_NO_EXPRESSION, loc),
+        )
+        return
+      }
+
       if (expr === null) {
         // TODO: Vue 3.4 supported shorthand syntax
         // https://github.com/vuejs/core/pull/9451
@@ -371,6 +393,13 @@ function transformProp(
       break
     }
     case 'on': {
+      if (!exp && !modifiers.length) {
+        ctx.options.onError!(
+          createCompilerError(ErrorCodes.VAPOR_ON_NO_EXPRESSION, loc),
+        )
+        return
+      }
+
       if (!node.arg) {
         // TODO support v-on="{}"
         return