refactor(compiler-vapor): errors

This commit is contained in:
三咲智子 Kevin Deng 2023-12-01 08:05:43 +08:00
parent cfd6d40d72
commit 0d9f0867d7
No known key found for this signature in database
GPG Key ID: 69992F2250DFD93E
7 changed files with 54 additions and 46 deletions

View File

@ -26,6 +26,8 @@ export {
ErrorCodes, ErrorCodes,
errorMessages, errorMessages,
createCompilerError, createCompilerError,
defaultOnError,
defaultOnWarn,
type CoreCompilerError, type CoreCompilerError,
type CompilerError type CompilerError
} from './errors' } from './errors'

View File

@ -48,7 +48,7 @@ if (__TEST__) {
} }
} }
export const DOMErrorMessages: { [code: number]: string } = { export const DOMErrorMessages: Record<DOMErrorCodes, string> = {
[DOMErrorCodes.X_V_HTML_NO_EXPRESSION]: `v-html is missing expression.`, [DOMErrorCodes.X_V_HTML_NO_EXPRESSION]: `v-html is missing expression.`,
[DOMErrorCodes.X_V_HTML_WITH_CHILDREN]: `v-html will override element children.`, [DOMErrorCodes.X_V_HTML_WITH_CHILDREN]: `v-html will override element children.`,
[DOMErrorCodes.X_V_TEXT_NO_EXPRESSION]: `v-text is missing expression.`, [DOMErrorCodes.X_V_TEXT_NO_EXPRESSION]: `v-text is missing expression.`,
@ -59,5 +59,8 @@ export const DOMErrorMessages: { [code: number]: string } = {
[DOMErrorCodes.X_V_MODEL_UNNECESSARY_VALUE]: `Unnecessary value binding used alongside v-model. It will interfere with v-model's behavior.`, [DOMErrorCodes.X_V_MODEL_UNNECESSARY_VALUE]: `Unnecessary value binding used alongside v-model. It will interfere with v-model's behavior.`,
[DOMErrorCodes.X_V_SHOW_NO_EXPRESSION]: `v-show is missing expression.`, [DOMErrorCodes.X_V_SHOW_NO_EXPRESSION]: `v-show is missing expression.`,
[DOMErrorCodes.X_TRANSITION_INVALID_CHILDREN]: `<Transition> expects exactly one child element or component.`, [DOMErrorCodes.X_TRANSITION_INVALID_CHILDREN]: `<Transition> expects exactly one child element or component.`,
[DOMErrorCodes.X_IGNORED_SIDE_EFFECT_TAG]: `Tags with side effect (<script> and <style>) are ignored in client component templates.` [DOMErrorCodes.X_IGNORED_SIDE_EFFECT_TAG]: `Tags with side effect (<script> and <style>) are ignored in client component templates.`,
// just to fulfill types
[DOMErrorCodes.__EXTEND_POINT__]: ``
} }

View File

@ -1,9 +1,5 @@
import { type RootNode, BindingTypes } from '@vue/compiler-dom' import { type RootNode, BindingTypes, ErrorCodes } from '@vue/compiler-dom'
import { import { type CompilerOptions, compile as _compile } from '../src'
type CompilerOptions,
VaporErrorCodes,
compile as _compile,
} from '../src'
// TODO remove it // TODO remove it
import { format } from 'prettier' import { format } from 'prettier'
@ -82,7 +78,7 @@ describe('compile', () => {
await compile(`<div v-bind:arg />`, { onError }) await compile(`<div v-bind:arg />`, { onError })
expect(onError.mock.calls[0][0]).toMatchObject({ expect(onError.mock.calls[0][0]).toMatchObject({
code: VaporErrorCodes.X_VAPOR_BIND_NO_EXPRESSION, code: ErrorCodes.X_V_BIND_NO_EXPRESSION,
loc: { loc: {
start: { start: {
line: 1, line: 1,
@ -111,7 +107,7 @@ describe('compile', () => {
const onError = vi.fn() const onError = vi.fn()
await compile(`<div v-on:click />`, { onError }) await compile(`<div v-on:click />`, { onError })
expect(onError.mock.calls[0][0]).toMatchObject({ expect(onError.mock.calls[0][0]).toMatchObject({
code: VaporErrorCodes.X_VAPOR_ON_NO_EXPRESSION, code: ErrorCodes.X_V_ON_NO_EXPRESSION,
loc: { loc: {
start: { start: {
line: 1, line: 1,

View File

@ -4,11 +4,13 @@ import {
type RootNode, type RootNode,
type DirectiveTransform, type DirectiveTransform,
parse, parse,
defaultOnError,
createCompilerError,
ErrorCodes,
} from '@vue/compiler-dom' } from '@vue/compiler-dom'
import { extend, isString } from '@vue/shared' import { extend, isString } from '@vue/shared'
import { NodeTransform, transform } from './transform' import { NodeTransform, transform } from './transform'
import { generate } from './generate' import { generate } from './generate'
import { defaultOnError, createCompilerError, VaporErrorCodes } from './errors'
import { transformOnce } from './transforms/vOnce' import { transformOnce } from './transforms/vOnce'
import { HackOptions } from './hack' import { HackOptions } from './hack'
@ -25,9 +27,9 @@ export function compile(
/* istanbul ignore if */ /* istanbul ignore if */
if (__BROWSER__) { if (__BROWSER__) {
if (options.prefixIdentifiers === true) { if (options.prefixIdentifiers === true) {
onError(createCompilerError(VaporErrorCodes.X_PREFIX_ID_NOT_SUPPORTED)) onError(createCompilerError(ErrorCodes.X_PREFIX_ID_NOT_SUPPORTED))
} else if (isModuleMode) { } else if (isModuleMode) {
onError(createCompilerError(VaporErrorCodes.X_MODULE_MODE_NOT_SUPPORTED)) onError(createCompilerError(ErrorCodes.X_MODULE_MODE_NOT_SUPPORTED))
} }
} }

View File

@ -1,29 +1,32 @@
import type { CompilerError } from '@vue/compiler-dom' import {
CompilerError,
SourceLocation,
createCompilerError,
} from '@vue/compiler-dom'
export { createCompilerError } from '@vue/compiler-dom' export interface VaporCompilerError extends CompilerError {
export function defaultOnError(error: CompilerError) { code: VaporErrorCodes
throw error
} }
export function defaultOnWarn(msg: CompilerError) { export function createVaporCompilerError(
__DEV__ && console.warn(`[Vue warn] ${msg.message}`) code: VaporErrorCodes,
loc?: SourceLocation,
) {
return createCompilerError(
code,
loc,
__DEV__ || !__BROWSER__ ? VaporErrorMessages : undefined,
) as VaporCompilerError
} }
export enum VaporErrorCodes { export enum VaporErrorCodes {
// transform errors X_V_PLACEHOLDER = 100,
X_VAPOR_BIND_NO_EXPRESSION, __EXTEND_POINT__,
X_VAPOR_ON_NO_EXPRESSION,
// generic errors
X_PREFIX_ID_NOT_SUPPORTED,
X_MODULE_MODE_NOT_SUPPORTED,
} }
export const errorMessages: Record<VaporErrorCodes, string> = { export const VaporErrorMessages: Record<VaporErrorCodes, string> = {
// transform errors [VaporErrorCodes.X_V_PLACEHOLDER]: `[placeholder]`,
[VaporErrorCodes.X_VAPOR_BIND_NO_EXPRESSION]: `v-bind is missing expression.`,
[VaporErrorCodes.X_VAPOR_ON_NO_EXPRESSION]: `v-on is missing expression.`,
[VaporErrorCodes.X_PREFIX_ID_NOT_SUPPORTED]: `"prefixIdentifiers" option is not supported in this build of compiler.`, // just to fulfill types
[VaporErrorCodes.X_MODULE_MODE_NOT_SUPPORTED]: `ES module mode is not supported in this build of compiler.`, [VaporErrorCodes.__EXTEND_POINT__]: ``,
} }

View File

@ -9,24 +9,22 @@ import {
type ExpressionNode, type ExpressionNode,
type ParentNode, type ParentNode,
type AllNode, type AllNode,
type CompilerCompatOptions,
NodeTypes, NodeTypes,
BindingTypes, BindingTypes,
CompilerCompatOptions, defaultOnError,
defaultOnWarn,
ErrorCodes,
createCompilerError,
} from '@vue/compiler-dom' } from '@vue/compiler-dom'
import { EMPTY_OBJ, NOOP, isArray, isVoidTag } from '@vue/shared'
import { import {
type OperationNode, type OperationNode,
type RootIRNode, type RootIRNode,
IRNodeTypes, IRNodeTypes,
DynamicInfo, DynamicInfo,
} from './ir' } from './ir'
import { EMPTY_OBJ, NOOP, isArray, isVoidTag } from '@vue/shared' import type { HackOptions } from './hack'
import {
VaporErrorCodes,
createCompilerError,
defaultOnError,
defaultOnWarn,
} from './errors'
import { HackOptions } from './hack'
export type NodeTransform = ( export type NodeTransform = (
node: RootNode | TemplateChildNode, node: RootNode | TemplateChildNode,
@ -438,7 +436,7 @@ function transformProp(
(exp.type === NodeTypes.SIMPLE_EXPRESSION && !exp.content.trim()) (exp.type === NodeTypes.SIMPLE_EXPRESSION && !exp.content.trim())
) { ) {
ctx.options.onError!( ctx.options.onError!(
createCompilerError(VaporErrorCodes.X_VAPOR_BIND_NO_EXPRESSION, loc), createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, loc),
) )
return return
} }
@ -467,7 +465,7 @@ function transformProp(
case 'on': { case 'on': {
if (!exp && !modifiers.length) { if (!exp && !modifiers.length) {
ctx.options.onError!( ctx.options.onError!(
createCompilerError(VaporErrorCodes.X_VAPOR_ON_NO_EXPRESSION, loc), createCompilerError(ErrorCodes.X_V_ON_NO_EXPRESSION, loc),
) )
return return
} }

View File

@ -5,8 +5,12 @@ const dirname = path.dirname(new URL(import.meta.url).pathname)
const resolve = (/** @type {string} */ p) => const resolve = (/** @type {string} */ p) =>
path.resolve(dirname, '../../packages', p) path.resolve(dirname, '../../packages', p)
/** @returns {import('vite').Plugin} */ /**
export function DevPlugin() { * @param {Object} [env]
* @param {boolean} [env.browser]
* @returns {import('vite').Plugin}
*/
export function DevPlugin({ browser = false } = {}) {
return { return {
name: 'dev-plugin', name: 'dev-plugin',
config() { config() {
@ -39,7 +43,7 @@ export function DevPlugin() {
// this is only used during Vue's internal tests // this is only used during Vue's internal tests
__TEST__: `false`, __TEST__: `false`,
// If the build is expected to run directly in the browser (global / esm builds) // If the build is expected to run directly in the browser (global / esm builds)
__BROWSER__: String(true), __BROWSER__: String(browser),
__GLOBAL__: String(false), __GLOBAL__: String(false),
__ESM_BUNDLER__: String(true), __ESM_BUNDLER__: String(true),
__ESM_BROWSER__: String(false), __ESM_BROWSER__: String(false),