]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor: move compile into compiler-core
authorEvan You <yyx990803@gmail.com>
Fri, 20 Sep 2019 16:16:19 +0000 (12:16 -0400)
committerEvan You <yyx990803@gmail.com>
Fri, 20 Sep 2019 16:16:19 +0000 (12:16 -0400)
12 files changed:
packages/compiler-core/__tests__/transform.spec.ts
packages/compiler-core/src/codegen.ts
packages/compiler-core/src/directives/vFor.ts
packages/compiler-core/src/directives/vIf.ts
packages/compiler-core/src/errors.ts
packages/compiler-core/src/index.ts
packages/compiler-core/src/parse.ts
packages/compiler-core/src/transform.ts
packages/compiler-dom/src/index.ts
packages/runtime-core/src/component.ts
packages/runtime-core/src/index.ts
packages/vue/src/index.ts

index 87cb9326a3d09cbfaa8a2ae2eac256245251d2b1..e6d8ef058248fd609e1b93b6012063f094203728 100644 (file)
@@ -164,7 +164,7 @@ describe('compiler: transform', () => {
     const ast = parse(`<div/>`)
     const loc = ast.children[0].loc.start
     const plugin: Transform = (node, context) => {
-      context.onError(
+      context.emitError(
         createCompilerError(ErrorCodes.X_INVALID_END_TAG, node.loc.start)
       )
     }
index 52b348b56b0607d50fa87b97cef63a778bed3eb0..857aa92a3631fb4a3105afd4f6ddee5c6bfd8bd1 100644 (file)
@@ -66,12 +66,11 @@ export function generate(
 
 function createCodegenContext(
   ast: RootNode,
-  options: CodegenOptions
+  { module = false, filename = `template.vue.html` }: CodegenOptions
 ): CodegenContext {
   const context: CodegenContext = {
-    module: false,
-    filename: `template.vue.html`,
-    ...options,
+    module,
+    filename,
     source: ast.loc.source,
     code: ``,
     column: 1,
index 095d201ceeecdbd5cd709f18446885a6d0f88610..668fbd124a5cf8fb6699c7eb56d63a06b3dcaf21 100644 (file)
@@ -27,7 +27,7 @@ export const transformFor = createDirectiveTransform(
           children: [node]
         })
       } else {
-        context.onError(
+        context.emitError(
           createCompilerError(
             ErrorCodes.X_FOR_MALFORMED_EXPRESSION,
             dir.loc.start
@@ -35,7 +35,7 @@ export const transformFor = createDirectiveTransform(
         )
       }
     } else {
-      context.onError(
+      context.emitError(
         createCompilerError(ErrorCodes.X_FOR_NO_EXPRESSION, dir.loc.start)
       )
     }
index 09898997bc80cf7739286465f05c207cd0d2790f..cbdf8be9583e74cf1055629909f7bb2094b35ab5 100644 (file)
@@ -38,7 +38,7 @@ export const transformIf = createDirectiveTransform(
           }
           sibling.branches.push(branch)
         } else {
-          context.onError(
+          context.emitError(
             createCompilerError(
               dir.name === 'else'
                 ? ErrorCodes.X_ELSE_NO_ADJACENT_IF
index e6288ac6c25a65fc6164492da0554a04a89c9873..5467715fdd6570f4cbae0dea7371a0b2e3edb520 100644 (file)
@@ -5,6 +5,10 @@ export interface CompilerError extends SyntaxError {
   loc: Position
 }
 
+export function defaultOnError(error: CompilerError) {
+  throw error
+}
+
 export function createCompilerError(
   code: ErrorCodes,
   loc: Position
index 250bebcfe6b7527cea81e38d1139e3e342e5419d..495933aceca02a3bc461497a4b49628da5189915 100644 (file)
@@ -1,11 +1,35 @@
+import { parse, ParserOptions } from './parse'
+import { transform, TransformOptions } from './transform'
+import { generate, CodegenOptions, CodegenResult } from './codegen'
+
+export type CompilerOptions = ParserOptions & TransformOptions & CodegenOptions
+
+export function compile(
+  template: string,
+  options: CompilerOptions = {}
+): CodegenResult {
+  const ast = parse(template, options)
+
+  transform(ast, {
+    ...options,
+    transforms: [
+      // TODO include built-in core transforms
+      ...(options.transforms || []) // user transforms
+    ]
+  })
+
+  return generate(ast, options)
+}
+
+// Also expose lower level APIs & types
 export { parse, ParserOptions, TextModes } from './parse'
 export {
   transform,
   createDirectiveTransform,
   TransformOptions,
-  Transform
+  Transform,
+  DirectiveTransform
 } from './transform'
 export { generate, CodegenOptions, CodegenResult } from './codegen'
 export { ErrorCodes, CompilerError, createCompilerError } from './errors'
-
 export * from './ast'
index 0012e379c064551c9ffd70bf317246fe31322094..0a9521ad5bb2898ef747145ddd58a2e0c111d7cc 100644 (file)
@@ -1,4 +1,9 @@
-import { ErrorCodes, CompilerError, createCompilerError } from './errors'
+import {
+  ErrorCodes,
+  CompilerError,
+  createCompilerError,
+  defaultOnError
+} from './errors'
 import {
   assert,
   advancePositionWithMutation,
@@ -48,9 +53,7 @@ export const defaultParserOptions: Required<ParserOptions> = {
     'apos;': "'",
     'quot;': '"'
   },
-  onError(error: CompilerError): void {
-    throw error
-  }
+  onError: defaultOnError
 }
 
 export const enum TextModes {
@@ -62,7 +65,8 @@ export const enum TextModes {
   ATTRIBUTE_VALUE
 }
 
-interface ParserContext extends Required<ParserOptions> {
+interface ParserContext {
+  options: Required<ParserOptions>
   readonly originalSource: string
   source: string
   offset: number
@@ -87,8 +91,10 @@ function createParserContext(
   options: ParserOptions
 ): ParserContext {
   return {
-    ...defaultParserOptions,
-    ...options,
+    options: {
+      ...defaultParserOptions,
+      ...options
+    },
     column: 1,
     line: 1,
     offset: 0,
@@ -115,7 +121,7 @@ function parseChildren(
     const s = context.source
     let node: any = null
 
-    if (startsWith(s, context.delimiters[0])) {
+    if (startsWith(s, context.options.delimiters[0])) {
       // '{{'
       node = parseInterpolation(context, mode)
     } else if (mode === TextModes.DATA && s[0] === '<') {
@@ -194,7 +200,11 @@ function pushNode(
   if (!__DEV__ && node.type === NodeTypes.COMMENT) {
     return
   }
-  if (context.ignoreSpaces && node.type === NodeTypes.TEXT && node.isEmpty) {
+  if (
+    context.options.ignoreSpaces &&
+    node.type === NodeTypes.TEXT &&
+    node.isEmpty
+  ) {
     return
   }
 
@@ -311,13 +321,13 @@ function parseElement(
   const parent = last(ancestors)
   const element = parseTag(context, TagType.Start, parent)
 
-  if (element.isSelfClosing || context.isVoidTag(element.tag)) {
+  if (element.isSelfClosing || context.options.isVoidTag(element.tag)) {
     return element
   }
 
   // Children.
   ancestors.push(element)
-  const mode = (context.getTextMode(
+  const mode = (context.options.getTextMode(
     element.tag,
     element.ns
   ) as unknown) as TextModes
@@ -368,7 +378,7 @@ function parseTag(
   const tag = match[1]
   const attrs = []
   const directives = []
-  const ns = context.getNamespace(tag, parent)
+  const ns = context.options.getNamespace(tag, parent)
 
   advanceBy(context, match[0].length)
   advanceSpaces(context)
@@ -601,7 +611,7 @@ function parseInterpolation(
   context: ParserContext,
   mode: TextModes
 ): ExpressionNode | undefined {
-  const [open, close] = context.delimiters
+  const [open, close] = context.options.delimiters
   __DEV__ && assert(startsWith(context.source, open))
 
   const closeIndex = context.source.indexOf(close, open.length)
@@ -626,7 +636,7 @@ function parseInterpolation(
 function parseText(context: ParserContext, mode: TextModes): TextNode {
   __DEV__ && assert(context.source.length > 0)
 
-  const [open] = context.delimiters
+  const [open] = context.options.delimiters
   const endIndex = Math.min(
     ...[
       context.source.indexOf('<', 1),
@@ -691,7 +701,7 @@ function parseTextData(
           --length
         ) {
           name = context.source.substr(1, length)
-          value = context.namedCharacterReferences[name]
+          value = context.options.namedCharacterReferences[name]
         }
         if (value) {
           const semi = name.endsWith(';')
@@ -837,7 +847,7 @@ function emitError(
     loc.offset += offset
     loc.column += offset
   }
-  context.onError(createCompilerError(code, loc))
+  context.options.onError(createCompilerError(code, loc))
 }
 
 function isEnd(
index 7db018a322be29c58c9310325652be8b2e985ea8..3f97359ff36eaaeb9041586770fff5e66119de68 100644 (file)
@@ -7,7 +7,7 @@ import {
   DirectiveNode
 } from './ast'
 import { isString } from '@vue/shared'
-import { CompilerError } from './errors'
+import { CompilerError, defaultOnError } from './errors'
 
 export type Transform = (node: ChildNode, context: TransformContext) => void
 
@@ -18,11 +18,13 @@ export type DirectiveTransform = (
 ) => false | void
 
 export interface TransformOptions {
-  transforms: Transform[]
+  transforms?: Transform[]
   onError?: (error: CompilerError) => void
 }
 
-interface TransformContext extends Required<TransformOptions> {
+interface TransformContext {
+  transforms: Transform[]
+  emitError: (error: CompilerError) => void
   parent: ParentNode
   ancestors: ParentNode[]
   childIndex: number
@@ -42,10 +44,8 @@ function createTransformContext(
   options: TransformOptions
 ): TransformContext {
   const context: TransformContext = {
-    onError(error: CompilerError) {
-      throw error
-    },
-    ...options,
+    transforms: options.transforms || [],
+    emitError: options.onError || defaultOnError,
     parent: root,
     ancestors: [],
     childIndex: 0,
@@ -109,7 +109,7 @@ function traverseNode(
   ancestors: ParentNode[]
 ) {
   // apply transform plugins
-  const transforms = context.transforms
+  const { transforms } = context
   for (let i = 0; i < transforms.length; i++) {
     const plugin = transforms[i]
     plugin(node, context)
index 47c58e09f100d09bd4ab3ca98ab35171e0b33896..7b636355ba5cb2d77d6d2be760ae6acf4d06b5b8 100644 (file)
@@ -1,46 +1,23 @@
 import {
-  parse,
-  transform,
-  generate,
-  CompilerError,
-  Transform,
+  compile as baseCompile,
+  CompilerOptions,
   CodegenResult
 } from '@vue/compiler-core'
 import { parserOptionsMinimal } from './parserOptionsMinimal'
 import { parserOptionsStandard } from './parserOptionsStandard'
 
-const parserOptions = __BROWSER__ ? parserOptionsMinimal : parserOptionsStandard
-
-export interface CompilerOptions {
-  module?: boolean
-  onError?(err: CompilerError): void
-  transforms?: Transform[]
-}
-
 export function compile(
   template: string,
   options: CompilerOptions = {}
 ): CodegenResult {
-  const {
-    module = false,
-    onError = (err: CompilerError) => {
-      throw err
-    },
-    transforms = []
-  } = options
-  const ast = parse(template, {
-    ...parserOptions,
-    onError
-  })
-  transform(ast, {
+  return baseCompile(template, {
+    ...options,
+    ...(__BROWSER__ ? parserOptionsMinimal : parserOptionsStandard),
     transforms: [
-      // TODO include core transforms
-      // TODO include DOM transforms
-      ...transforms // user transforms
-    ],
-    onError
+      // TODO include DOM-specific transforms
+      ...(options.transforms || []) // extra user transforms
+    ]
   })
-  return generate(ast, { module })
 }
 
 export * from '@vue/compiler-core'
index cf79af418319de2464792338e431188490d0f195..d99a636f8d9168cac697043080bd8b67d83373e2 100644 (file)
@@ -24,6 +24,7 @@ import {
   isObject
 } from '@vue/shared'
 import { SuspenseBoundary } from './suspense'
+import { CompilerOptions } from '@vue/compiler-dom'
 
 export type Data = { [key: string]: unknown }
 
@@ -61,7 +62,7 @@ export interface SetupContext {
   emit: Emit
 }
 
-type RenderFunction = () => VNodeChild
+export type RenderFunction = () => VNodeChild
 
 export interface ComponentInternalInstance {
   type: FunctionalComponent | ComponentOptions
@@ -298,8 +299,14 @@ export function handleSetupResult(
   finishComponentSetup(instance, parentSuspense)
 }
 
-let compile: Function | undefined
-export function registerCompiler(_compile: Function) {
+type CompileFunction = (
+  template: string,
+  options?: CompilerOptions
+) => RenderFunction
+
+let compile: CompileFunction | undefined
+
+export function registerRuntimeCompiler(_compile: CompileFunction) {
   compile = _compile
 }
 
@@ -311,7 +318,9 @@ function finishComponentSetup(
   if (!instance.render) {
     if (Component.template && !Component.render) {
       if (compile) {
-        Component.render = compile(Component.template)
+        Component.render = compile(Component.template, {
+          onError(err) {}
+        })
       } else if (__DEV__) {
         warn(
           `Component provides template but the build of Vue you are running ` +
index cd81043faa4fac88ede486fb3d4730e41059f1b1..006ecf647d478f5f1021584a384c00badb3bb959 100644 (file)
@@ -40,7 +40,7 @@ export { applyDirectives } from './directives'
 export { resolveComponent, resolveDirective } from './componentOptions'
 
 // Internal, for integration with runtime compiler
-export { registerCompiler } from './component'
+export { registerRuntimeCompiler } from './component'
 
 // Types -----------------------------------------------------------------------
 
@@ -50,7 +50,8 @@ export { VNode, VNodeTypes } from './vnode'
 export {
   Component,
   FunctionalComponent,
-  ComponentInternalInstance
+  ComponentInternalInstance,
+  RenderFunction
 } from './component'
 export {
   ComponentOptions,
@@ -58,6 +59,7 @@ export {
   ComponentOptionsWithProps,
   ComponentOptionsWithArrayProps
 } from './componentOptions'
+
 export { ComponentPublicInstance } from './componentPublicInstanceProxy'
 export { RendererOptions } from './createRenderer'
 export { Slot, Slots } from './componentSlots'
index 7635080ad53c87bbbb7a89bcdae237564a8ecdad..1c89caba337d12be1e3a56df65a8924c182f0a87 100644 (file)
@@ -1,15 +1,19 @@
 // This package is the "full-build" that includes both the runtime
 // and the compiler, and supports on-the-fly compilation of the template option.
-import { compile as baseCompile, CompilerOptions } from '@vue/compiler-dom'
-import { registerCompiler } from '@vue/runtime-dom'
+import { compile, CompilerOptions } from '@vue/compiler-dom'
+import { registerRuntimeCompiler, RenderFunction } from '@vue/runtime-dom'
 
-export function compile(template: string, options?: CompilerOptions): Function {
-  const { code } = baseCompile(template, options)
-  return new Function(`with(this){return ${code}}`)
+function compileToFunction(
+  template: string,
+  options?: CompilerOptions
+): RenderFunction {
+  const { code } = compile(template, options)
+  return new Function(`with(this){return ${code}}`) as RenderFunction
 }
 
-registerCompiler(compile)
+registerRuntimeCompiler(compileToFunction)
 
+export { compileToFunction as compile }
 export * from '@vue/runtime-dom'
 
 if (__BROWSER__ && __DEV__) {