mirror of https://github.com/vuejs/core.git
refactor(compiler-vapor): class-based CodegenContext
This commit is contained in:
parent
e02725665d
commit
b8806f0954
|
@ -44,111 +44,94 @@ export type CodeFragment =
|
||||||
| [code: string, newlineIndex?: number, loc?: SourceLocation, name?: string]
|
| [code: string, newlineIndex?: number, loc?: SourceLocation, name?: string]
|
||||||
| undefined
|
| undefined
|
||||||
|
|
||||||
export interface CodegenContext {
|
export class CodegenContext {
|
||||||
options: Required<CodegenOptions>
|
options: Required<CodegenOptions>
|
||||||
|
|
||||||
source: string
|
source: string
|
||||||
code: CodeFragment[]
|
code: CodeFragment[]
|
||||||
indentLevel: number
|
indentLevel: number = 0
|
||||||
map?: SourceMapGenerator
|
map?: SourceMapGenerator
|
||||||
|
|
||||||
push(...args: CodeFragment[]): void
|
push: (...args: CodeFragment[]) => void
|
||||||
newline(): CodeFragment
|
newline = (): CodeFragment => {
|
||||||
multi(
|
return [`\n${` `.repeat(this.indentLevel)}`, NewlineType.Start]
|
||||||
codes: [left: string, right: string, segment: string],
|
}
|
||||||
...fn: Array<false | string | CodeFragment[]>
|
multi = (
|
||||||
): CodeFragment[]
|
[left, right, seg]: [left: string, right: string, segment: string],
|
||||||
call(
|
...fns: Array<false | string | CodeFragment[]>
|
||||||
|
): CodeFragment[] => {
|
||||||
|
const frag: CodeFragment[] = []
|
||||||
|
fns = fns.filter(Boolean)
|
||||||
|
frag.push(left)
|
||||||
|
for (let [i, fn] of fns.entries()) {
|
||||||
|
if (fn) {
|
||||||
|
if (isString(fn)) fn = [fn]
|
||||||
|
frag.push(...fn)
|
||||||
|
if (i < fns.length - 1) frag.push(seg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
frag.push(right)
|
||||||
|
return frag
|
||||||
|
}
|
||||||
|
call = (
|
||||||
name: string,
|
name: string,
|
||||||
...args: Array<false | string | CodeFragment[]>
|
...args: Array<false | string | CodeFragment[]>
|
||||||
): CodeFragment[]
|
): CodeFragment[] => {
|
||||||
withIndent<T>(fn: () => T): T
|
return [name, ...this.multi(['(', ')', ', '], ...args)]
|
||||||
|
}
|
||||||
helpers: Set<string>
|
withIndent = <T>(fn: () => T): T => {
|
||||||
vaporHelpers: Set<string>
|
++this.indentLevel
|
||||||
helper(name: string): string
|
const ret = fn()
|
||||||
vaporHelper(name: VaporHelper): string
|
--this.indentLevel
|
||||||
}
|
return ret
|
||||||
|
|
||||||
function createCodegenContext(ir: RootIRNode, options: CodegenOptions) {
|
|
||||||
const helpers = new Set<string>([])
|
|
||||||
const vaporHelpers = new Set<string>([])
|
|
||||||
const [code, push] = buildCodeFragment()
|
|
||||||
const context: CodegenContext = {
|
|
||||||
options: extend(
|
|
||||||
{
|
|
||||||
mode: 'function',
|
|
||||||
prefixIdentifiers: options.mode === 'module',
|
|
||||||
sourceMap: false,
|
|
||||||
filename: `template.vue.html`,
|
|
||||||
scopeId: null,
|
|
||||||
optimizeImports: false,
|
|
||||||
runtimeGlobalName: `Vue`,
|
|
||||||
runtimeModuleName: `vue`,
|
|
||||||
ssrRuntimeModuleName: 'vue/server-renderer',
|
|
||||||
ssr: false,
|
|
||||||
isTS: false,
|
|
||||||
inSSR: false,
|
|
||||||
inline: false,
|
|
||||||
bindingMetadata: {},
|
|
||||||
expressionPlugins: [],
|
|
||||||
},
|
|
||||||
options,
|
|
||||||
),
|
|
||||||
|
|
||||||
source: ir.source,
|
|
||||||
code,
|
|
||||||
indentLevel: 0,
|
|
||||||
|
|
||||||
helpers,
|
|
||||||
vaporHelpers,
|
|
||||||
helper(name: string) {
|
|
||||||
helpers.add(name)
|
|
||||||
return `_${name}`
|
|
||||||
},
|
|
||||||
vaporHelper(name: VaporHelper) {
|
|
||||||
vaporHelpers.add(name)
|
|
||||||
return `_${name}`
|
|
||||||
},
|
|
||||||
|
|
||||||
push,
|
|
||||||
newline() {
|
|
||||||
return [`\n${` `.repeat(context.indentLevel)}`, NewlineType.Start]
|
|
||||||
},
|
|
||||||
multi([left, right, seg], ...fns) {
|
|
||||||
const frag: CodeFragment[] = []
|
|
||||||
fns = fns.filter(Boolean)
|
|
||||||
frag.push(left)
|
|
||||||
for (let [i, fn] of fns.entries()) {
|
|
||||||
if (fn) {
|
|
||||||
if (isString(fn)) fn = [fn]
|
|
||||||
frag.push(...fn)
|
|
||||||
if (i < fns.length - 1) frag.push(seg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
frag.push(right)
|
|
||||||
return frag
|
|
||||||
},
|
|
||||||
call(name, ...args) {
|
|
||||||
return [name, ...context.multi(['(', ')', ', '], ...args)]
|
|
||||||
},
|
|
||||||
withIndent(fn) {
|
|
||||||
++context.indentLevel
|
|
||||||
const ret = fn()
|
|
||||||
--context.indentLevel
|
|
||||||
return ret
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const filename = context.options.filename
|
helpers = new Set<string>([])
|
||||||
if (!__BROWSER__ && context.options.sourceMap) {
|
vaporHelpers = new Set<string>([])
|
||||||
// lazy require source-map implementation, only in non-browser builds
|
helper = (name: string) => {
|
||||||
context.map = new SourceMapGenerator()
|
this.helpers.add(name)
|
||||||
context.map.setSourceContent(filename, context.source)
|
return `_${name}`
|
||||||
context.map._sources.add(filename)
|
}
|
||||||
|
vaporHelper = (name: VaporHelper) => {
|
||||||
|
this.vaporHelpers.add(name)
|
||||||
|
return `_${name}`
|
||||||
}
|
}
|
||||||
|
|
||||||
return context
|
constructor(ir: RootIRNode, options: CodegenOptions) {
|
||||||
|
const defaultOptions = {
|
||||||
|
mode: 'function',
|
||||||
|
prefixIdentifiers: options.mode === 'module',
|
||||||
|
sourceMap: false,
|
||||||
|
filename: `template.vue.html`,
|
||||||
|
scopeId: null,
|
||||||
|
optimizeImports: false,
|
||||||
|
runtimeGlobalName: `Vue`,
|
||||||
|
runtimeModuleName: `vue`,
|
||||||
|
ssrRuntimeModuleName: 'vue/server-renderer',
|
||||||
|
ssr: false,
|
||||||
|
isTS: false,
|
||||||
|
inSSR: false,
|
||||||
|
inline: false,
|
||||||
|
bindingMetadata: {},
|
||||||
|
expressionPlugins: [],
|
||||||
|
}
|
||||||
|
this.options = extend(defaultOptions, options)
|
||||||
|
this.source = ir.source
|
||||||
|
|
||||||
|
const [code, push] = buildCodeFragment()
|
||||||
|
this.code = code
|
||||||
|
this.push = push
|
||||||
|
|
||||||
|
const {
|
||||||
|
options: { filename, sourceMap },
|
||||||
|
} = this
|
||||||
|
if (!__BROWSER__ && sourceMap) {
|
||||||
|
// lazy require source-map implementation, only in non-browser builds
|
||||||
|
this.map = new SourceMapGenerator()
|
||||||
|
this.map.setSourceContent(filename, this.source)
|
||||||
|
this.map._sources.add(filename)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VaporCodegenResult extends BaseCodegenResult {
|
export interface VaporCodegenResult extends BaseCodegenResult {
|
||||||
|
@ -162,7 +145,7 @@ export function generate(
|
||||||
ir: RootIRNode,
|
ir: RootIRNode,
|
||||||
options: CodegenOptions = {},
|
options: CodegenOptions = {},
|
||||||
): VaporCodegenResult {
|
): VaporCodegenResult {
|
||||||
const ctx = createCodegenContext(ir, options)
|
const ctx = new CodegenContext(ir, options)
|
||||||
const { push, withIndent, newline, helpers, vaporHelpers } = ctx
|
const { push, withIndent, newline, helpers, vaporHelpers } = ctx
|
||||||
|
|
||||||
const functionName = 'render'
|
const functionName = 'render'
|
||||||
|
|
Loading…
Reference in New Issue