mirror of https://github.com/vuejs/core.git
refactor(compiler-vapor): re-organize
This commit is contained in:
parent
1a8fb86c75
commit
edaa3a0649
|
@ -27,7 +27,7 @@ import { transformVModel } from './transforms/vModel'
|
||||||
import { transformVIf } from './transforms/vIf'
|
import { transformVIf } from './transforms/vIf'
|
||||||
import { transformVFor } from './transforms/vFor'
|
import { transformVFor } from './transforms/vFor'
|
||||||
|
|
||||||
export type CompilerOptions = HackOptions<BaseCompilerOptions>
|
export { wrapTemplate } from './transforms/utils'
|
||||||
|
|
||||||
// TODO: copied from @vue/compiler-core
|
// TODO: copied from @vue/compiler-core
|
||||||
// code/AST -> IR -> JS codegen
|
// code/AST -> IR -> JS codegen
|
||||||
|
@ -89,6 +89,7 @@ export function compile(
|
||||||
return generate(ir, resolvedOptions)
|
return generate(ir, resolvedOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CompilerOptions = HackOptions<BaseCompilerOptions>
|
||||||
export type TransformPreset = [
|
export type TransformPreset = [
|
||||||
NodeTransform[],
|
NodeTransform[],
|
||||||
Record<string, DirectiveTransform>,
|
Record<string, DirectiveTransform>,
|
||||||
|
|
|
@ -1,66 +1,35 @@
|
||||||
import {
|
import type {
|
||||||
type CodegenOptions as BaseCodegenOptions,
|
CodegenOptions as BaseCodegenOptions,
|
||||||
type BaseCodegenResult,
|
BaseCodegenResult,
|
||||||
NewlineType,
|
|
||||||
type Position,
|
|
||||||
type SourceLocation,
|
|
||||||
advancePositionWithMutation,
|
|
||||||
locStub,
|
|
||||||
} from '@vue/compiler-dom'
|
} from '@vue/compiler-dom'
|
||||||
import type { IREffect, RootIRNode, VaporHelper } from './ir'
|
import type { IREffect, RootIRNode, VaporHelper } from './ir'
|
||||||
import { SourceMapGenerator } from 'source-map-js'
|
import { SourceMapGenerator } from 'source-map-js'
|
||||||
import { extend, isArray, isString, remove } from '@vue/shared'
|
import { extend, remove } from '@vue/shared'
|
||||||
import type { ParserPlugin } from '@babel/parser'
|
import type { ParserPlugin } from '@babel/parser'
|
||||||
import { genBlockFunctionContent } from './generators/block'
|
import { genBlockFunctionContent } from './generators/block'
|
||||||
import { genTemplates } from './generators/template'
|
import { genTemplates } from './generators/template'
|
||||||
|
import {
|
||||||
|
type CodeFragment,
|
||||||
|
INDENT_END,
|
||||||
|
INDENT_START,
|
||||||
|
LF,
|
||||||
|
NEWLINE,
|
||||||
|
buildCodeFragment,
|
||||||
|
genCodeFragment,
|
||||||
|
} from './generators/utils'
|
||||||
|
|
||||||
interface CodegenOptions extends BaseCodegenOptions {
|
export * from './generators/utils'
|
||||||
|
|
||||||
|
export interface CodegenOptions extends BaseCodegenOptions {
|
||||||
expressionPlugins?: ParserPlugin[]
|
expressionPlugins?: ParserPlugin[]
|
||||||
}
|
}
|
||||||
|
|
||||||
type FalsyValue = false | null | undefined
|
|
||||||
export type CodeFragment =
|
|
||||||
| typeof NEWLINE
|
|
||||||
| typeof LF
|
|
||||||
| typeof INDENT_START
|
|
||||||
| typeof INDENT_END
|
|
||||||
| string
|
|
||||||
| [code: string, newlineIndex?: number, loc?: SourceLocation, name?: string]
|
|
||||||
| FalsyValue
|
|
||||||
|
|
||||||
type CodeFragments = Exclude<CodeFragment, any[]> | CodeFragment[]
|
|
||||||
|
|
||||||
export class CodegenContext {
|
export class CodegenContext {
|
||||||
options: Required<CodegenOptions>
|
options: Required<CodegenOptions>
|
||||||
|
|
||||||
code: CodeFragment[]
|
code: CodeFragment[]
|
||||||
map?: SourceMapGenerator
|
map?: SourceMapGenerator
|
||||||
|
|
||||||
push: (...args: CodeFragment[]) => void
|
push: (...args: CodeFragment[]) => void
|
||||||
multi = (
|
|
||||||
[left, right, seg]: [
|
|
||||||
left: CodeFragment,
|
|
||||||
right: CodeFragment,
|
|
||||||
segment: CodeFragment,
|
|
||||||
],
|
|
||||||
...fns: CodeFragments[]
|
|
||||||
): CodeFragment[] => {
|
|
||||||
const frag: CodeFragment[] = []
|
|
||||||
fns = fns.filter(Boolean)
|
|
||||||
frag.push(left)
|
|
||||||
for (let [i, fn] of (
|
|
||||||
fns as Array<Exclude<CodeFragments, FalsyValue>>
|
|
||||||
).entries()) {
|
|
||||||
if (!isArray(fn)) fn = [fn]
|
|
||||||
frag.push(...fn)
|
|
||||||
if (i < fns.length - 1) frag.push(seg)
|
|
||||||
}
|
|
||||||
frag.push(right)
|
|
||||||
return frag
|
|
||||||
}
|
|
||||||
call = (name: string, ...args: CodeFragments[]): CodeFragment[] => {
|
|
||||||
return [name, ...this.multi(['(', ')', ', '], ...args)]
|
|
||||||
}
|
|
||||||
|
|
||||||
helpers = new Set<string>([])
|
helpers = new Set<string>([])
|
||||||
vaporHelpers = new Set<string>([])
|
vaporHelpers = new Set<string>([])
|
||||||
|
@ -135,12 +104,6 @@ export interface VaporCodegenResult extends BaseCodegenResult {
|
||||||
vaporHelpers: Set<string>
|
vaporHelpers: Set<string>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const NEWLINE = Symbol(__DEV__ ? `newline` : ``)
|
|
||||||
/** increase offset but don't push actual code */
|
|
||||||
export const LF = Symbol(__DEV__ ? `line feed` : ``)
|
|
||||||
export const INDENT_START = Symbol(__DEV__ ? `indent start` : ``)
|
|
||||||
export const INDENT_END = Symbol(__DEV__ ? `indent end` : ``)
|
|
||||||
|
|
||||||
// IR -> JS codegen
|
// IR -> JS codegen
|
||||||
export function generate(
|
export function generate(
|
||||||
ir: RootIRNode,
|
ir: RootIRNode,
|
||||||
|
@ -193,102 +156,6 @@ export function generate(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function genCodeFragment(context: CodegenContext) {
|
|
||||||
let codegen = ''
|
|
||||||
const pos = { line: 1, column: 1, offset: 0 }
|
|
||||||
let indentLevel = 0
|
|
||||||
|
|
||||||
for (let frag of context.code) {
|
|
||||||
if (!frag) continue
|
|
||||||
|
|
||||||
if (frag === NEWLINE) {
|
|
||||||
frag = [`\n${` `.repeat(indentLevel)}`, NewlineType.Start]
|
|
||||||
} else if (frag === INDENT_START) {
|
|
||||||
indentLevel++
|
|
||||||
continue
|
|
||||||
} else if (frag === INDENT_END) {
|
|
||||||
indentLevel--
|
|
||||||
continue
|
|
||||||
} else if (frag === LF) {
|
|
||||||
pos.line++
|
|
||||||
pos.column = 0
|
|
||||||
pos.offset++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isString(frag)) frag = [frag]
|
|
||||||
|
|
||||||
let [code, newlineIndex = NewlineType.None, loc, name] = frag
|
|
||||||
codegen += code
|
|
||||||
|
|
||||||
if (!__BROWSER__ && context.map) {
|
|
||||||
if (loc) addMapping(loc.start, name)
|
|
||||||
if (newlineIndex === NewlineType.Unknown) {
|
|
||||||
// multiple newlines, full iteration
|
|
||||||
advancePositionWithMutation(pos, code)
|
|
||||||
} else {
|
|
||||||
// fast paths
|
|
||||||
pos.offset += code.length
|
|
||||||
if (newlineIndex === NewlineType.None) {
|
|
||||||
// no newlines; fast path to avoid newline detection
|
|
||||||
if (__TEST__ && code.includes('\n')) {
|
|
||||||
throw new Error(
|
|
||||||
`CodegenContext.push() called newlineIndex: none, but contains` +
|
|
||||||
`newlines: ${code.replace(/\n/g, '\\n')}`,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
pos.column += code.length
|
|
||||||
} else {
|
|
||||||
// single newline at known index
|
|
||||||
if (newlineIndex === NewlineType.End) {
|
|
||||||
newlineIndex = code.length - 1
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
__TEST__ &&
|
|
||||||
(code.charAt(newlineIndex) !== '\n' ||
|
|
||||||
code.slice(0, newlineIndex).includes('\n') ||
|
|
||||||
code.slice(newlineIndex + 1).includes('\n'))
|
|
||||||
) {
|
|
||||||
throw new Error(
|
|
||||||
`CodegenContext.push() called with newlineIndex: ${newlineIndex} ` +
|
|
||||||
`but does not conform: ${code.replace(/\n/g, '\\n')}`,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
pos.line++
|
|
||||||
pos.column = code.length - newlineIndex
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (loc && loc !== locStub) {
|
|
||||||
addMapping(loc.end)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return codegen
|
|
||||||
|
|
||||||
function addMapping(loc: Position, name: string | null = null) {
|
|
||||||
// we use the private property to directly add the mapping
|
|
||||||
// because the addMapping() implementation in source-map-js has a bunch of
|
|
||||||
// unnecessary arg and validation checks that are pure overhead in our case.
|
|
||||||
const { _names, _mappings } = context.map!
|
|
||||||
if (name !== null && !_names.has(name)) _names.add(name)
|
|
||||||
_mappings.add({
|
|
||||||
originalLine: loc.line,
|
|
||||||
originalColumn: loc.column - 1, // source-map column is 0 based
|
|
||||||
generatedLine: pos.line,
|
|
||||||
generatedColumn: pos.column - 1,
|
|
||||||
source: context.options.filename,
|
|
||||||
// @ts-expect-error it is possible to be null
|
|
||||||
name,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function buildCodeFragment(...frag: CodeFragment[]) {
|
|
||||||
const push = frag.push.bind(frag)
|
|
||||||
return [frag, push] as const
|
|
||||||
}
|
|
||||||
|
|
||||||
function genHelperImports({ helpers, vaporHelpers, code }: CodegenContext) {
|
function genHelperImports({ helpers, vaporHelpers, code }: CodegenContext) {
|
||||||
let imports = ''
|
let imports = ''
|
||||||
if (helpers.size) {
|
if (helpers.size) {
|
||||||
|
|
|
@ -6,15 +6,16 @@ import {
|
||||||
} from '../ir'
|
} from '../ir'
|
||||||
import {
|
import {
|
||||||
type CodeFragment,
|
type CodeFragment,
|
||||||
type CodegenContext,
|
|
||||||
INDENT_END,
|
INDENT_END,
|
||||||
INDENT_START,
|
INDENT_START,
|
||||||
NEWLINE,
|
NEWLINE,
|
||||||
buildCodeFragment,
|
buildCodeFragment,
|
||||||
} from '../generate'
|
} from './utils'
|
||||||
|
import type { CodegenContext } from '../generate'
|
||||||
import { genWithDirective } from './directive'
|
import { genWithDirective } from './directive'
|
||||||
import { genEffects, genOperations } from './operation'
|
import { genEffects, genOperations } from './operation'
|
||||||
import { genChildren } from './template'
|
import { genChildren } from './template'
|
||||||
|
import { genMulti } from './utils'
|
||||||
|
|
||||||
export function genBlockFunction(
|
export function genBlockFunction(
|
||||||
oper: BlockFunctionIRNode,
|
oper: BlockFunctionIRNode,
|
||||||
|
@ -37,7 +38,6 @@ export function genBlockFunctionContent(
|
||||||
ir: BlockFunctionIRNode | RootIRNode,
|
ir: BlockFunctionIRNode | RootIRNode,
|
||||||
context: CodegenContext,
|
context: CodegenContext,
|
||||||
): CodeFragment[] {
|
): CodeFragment[] {
|
||||||
const { multi } = context
|
|
||||||
const [frag, push] = buildCodeFragment()
|
const [frag, push] = buildCodeFragment()
|
||||||
|
|
||||||
if (ir.templateIndex > -1) {
|
if (ir.templateIndex > -1) {
|
||||||
|
@ -59,7 +59,7 @@ export function genBlockFunctionContent(
|
||||||
push(
|
push(
|
||||||
NEWLINE,
|
NEWLINE,
|
||||||
`return `,
|
`return `,
|
||||||
...multi(['[', ']', ', '], ...ir.returns.map(n => `n${n}`)),
|
...genMulti(['[', ']', ', '], ...ir.returns.map(n => `n${n}`)),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
push(NEWLINE, `return n${ir.dynamic.id}`)
|
push(NEWLINE, `return n${ir.dynamic.id}`)
|
||||||
|
|
|
@ -1,20 +1,24 @@
|
||||||
import { createSimpleExpression, isSimpleIdentifier } from '@vue/compiler-dom'
|
import { createSimpleExpression, isSimpleIdentifier } from '@vue/compiler-dom'
|
||||||
import { camelize } from '@vue/shared'
|
import { camelize } from '@vue/shared'
|
||||||
import { genExpression } from './expression'
|
import { genExpression } from './expression'
|
||||||
import { type CodeFragment, type CodegenContext, NEWLINE } from '../generate'
|
import type { CodegenContext } from '../generate'
|
||||||
|
import { type CodeFragment, NEWLINE, genCall, genMulti } from './utils'
|
||||||
import type { WithDirectiveIRNode } from '../ir'
|
import type { WithDirectiveIRNode } from '../ir'
|
||||||
|
|
||||||
export function genWithDirective(
|
export function genWithDirective(
|
||||||
opers: WithDirectiveIRNode[],
|
opers: WithDirectiveIRNode[],
|
||||||
context: CodegenContext,
|
context: CodegenContext,
|
||||||
): CodeFragment[] {
|
): CodeFragment[] {
|
||||||
const { call, multi, vaporHelper } = context
|
const { vaporHelper } = context
|
||||||
|
|
||||||
const element = `n${opers[0].element}`
|
const element = `n${opers[0].element}`
|
||||||
const directiveItems = opers.map(genDirective)
|
const directiveItems = opers.map(genDirective)
|
||||||
const directives = multi(['[', ']', ', '], ...directiveItems)
|
const directives = genMulti(['[', ']', ', '], ...directiveItems)
|
||||||
|
|
||||||
return [NEWLINE, ...call(vaporHelper('withDirectives'), element, directives)]
|
return [
|
||||||
|
NEWLINE,
|
||||||
|
...genCall(vaporHelper('withDirectives'), element, directives),
|
||||||
|
]
|
||||||
|
|
||||||
function genDirective({ dir, builtin }: WithDirectiveIRNode): CodeFragment[] {
|
function genDirective({ dir, builtin }: WithDirectiveIRNode): CodeFragment[] {
|
||||||
const NULL = 'void 0'
|
const NULL = 'void 0'
|
||||||
|
@ -34,7 +38,7 @@ export function genWithDirective(
|
||||||
? ['{ ', genDirectiveModifiers(), ' }']
|
? ['{ ', genDirectiveModifiers(), ' }']
|
||||||
: false
|
: false
|
||||||
|
|
||||||
return multi(['[', ']', ', '], directive, value, argument, modifiers)
|
return genMulti(['[', ']', ', '], directive, value, argument, modifiers)
|
||||||
|
|
||||||
function genDirective() {
|
function genDirective() {
|
||||||
const {
|
const {
|
||||||
|
|
|
@ -1,20 +1,21 @@
|
||||||
import { type CodeFragment, type CodegenContext, NEWLINE } from '../generate'
|
import type { CodegenContext } from '../generate'
|
||||||
import type {
|
import type {
|
||||||
AppendNodeIRNode,
|
AppendNodeIRNode,
|
||||||
InsertNodeIRNode,
|
InsertNodeIRNode,
|
||||||
PrependNodeIRNode,
|
PrependNodeIRNode,
|
||||||
} from '../ir'
|
} from '../ir'
|
||||||
|
import { type CodeFragment, NEWLINE, genCall } from './utils'
|
||||||
|
|
||||||
export function genInsertNode(
|
export function genInsertNode(
|
||||||
oper: InsertNodeIRNode,
|
oper: InsertNodeIRNode,
|
||||||
{ call, vaporHelper }: CodegenContext,
|
{ vaporHelper }: CodegenContext,
|
||||||
): CodeFragment[] {
|
): CodeFragment[] {
|
||||||
const elements = ([] as number[]).concat(oper.element)
|
const elements = ([] as number[]).concat(oper.element)
|
||||||
let element = elements.map(el => `n${el}`).join(', ')
|
let element = elements.map(el => `n${el}`).join(', ')
|
||||||
if (elements.length > 1) element = `[${element}]`
|
if (elements.length > 1) element = `[${element}]`
|
||||||
return [
|
return [
|
||||||
NEWLINE,
|
NEWLINE,
|
||||||
...call(
|
...genCall(
|
||||||
vaporHelper('insert'),
|
vaporHelper('insert'),
|
||||||
element,
|
element,
|
||||||
`n${oper.parent}`,
|
`n${oper.parent}`,
|
||||||
|
@ -25,11 +26,11 @@ export function genInsertNode(
|
||||||
|
|
||||||
export function genPrependNode(
|
export function genPrependNode(
|
||||||
oper: PrependNodeIRNode,
|
oper: PrependNodeIRNode,
|
||||||
{ call, vaporHelper }: CodegenContext,
|
{ vaporHelper }: CodegenContext,
|
||||||
): CodeFragment[] {
|
): CodeFragment[] {
|
||||||
return [
|
return [
|
||||||
NEWLINE,
|
NEWLINE,
|
||||||
...call(
|
...genCall(
|
||||||
vaporHelper('prepend'),
|
vaporHelper('prepend'),
|
||||||
`n${oper.parent}`,
|
`n${oper.parent}`,
|
||||||
...oper.elements.map(el => `n${el}`),
|
...oper.elements.map(el => `n${el}`),
|
||||||
|
@ -39,11 +40,11 @@ export function genPrependNode(
|
||||||
|
|
||||||
export function genAppendNode(
|
export function genAppendNode(
|
||||||
oper: AppendNodeIRNode,
|
oper: AppendNodeIRNode,
|
||||||
{ call, vaporHelper }: CodegenContext,
|
{ vaporHelper }: CodegenContext,
|
||||||
): CodeFragment[] {
|
): CodeFragment[] {
|
||||||
return [
|
return [
|
||||||
NEWLINE,
|
NEWLINE,
|
||||||
...call(
|
...genCall(
|
||||||
vaporHelper('append'),
|
vaporHelper('append'),
|
||||||
`n${oper.parent}`,
|
`n${oper.parent}`,
|
||||||
...oper.elements.map(el => `n${el}`),
|
...oper.elements.map(el => `n${el}`),
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
import { isMemberExpression } from '@vue/compiler-dom'
|
import { isMemberExpression } from '@vue/compiler-dom'
|
||||||
|
import type { CodegenContext } from '../generate'
|
||||||
|
import type { SetEventIRNode } from '../ir'
|
||||||
|
import { genExpression } from './expression'
|
||||||
import {
|
import {
|
||||||
type CodeFragment,
|
type CodeFragment,
|
||||||
type CodegenContext,
|
|
||||||
INDENT_END,
|
INDENT_END,
|
||||||
INDENT_START,
|
INDENT_START,
|
||||||
NEWLINE,
|
NEWLINE,
|
||||||
buildCodeFragment,
|
buildCodeFragment,
|
||||||
} from '../generate'
|
genCall,
|
||||||
import type { SetEventIRNode } from '../ir'
|
} from './utils'
|
||||||
import { genExpression } from './expression'
|
|
||||||
|
|
||||||
// TODO: share this with compiler-core
|
// TODO: share this with compiler-core
|
||||||
const fnExpRE =
|
const fnExpRE =
|
||||||
|
@ -18,7 +19,7 @@ export function genSetEvent(
|
||||||
oper: SetEventIRNode,
|
oper: SetEventIRNode,
|
||||||
context: CodegenContext,
|
context: CodegenContext,
|
||||||
): CodeFragment[] {
|
): CodeFragment[] {
|
||||||
const { vaporHelper, call, options: ctxOptions } = context
|
const { vaporHelper, options: ctxOptions } = context
|
||||||
const { keys, nonKeys, options } = oper.modifiers
|
const { keys, nonKeys, options } = oper.modifiers
|
||||||
|
|
||||||
const name = genName()
|
const name = genName()
|
||||||
|
@ -32,7 +33,7 @@ export function genSetEvent(
|
||||||
|
|
||||||
return [
|
return [
|
||||||
NEWLINE,
|
NEWLINE,
|
||||||
...call(
|
...genCall(
|
||||||
vaporHelper('on'),
|
vaporHelper('on'),
|
||||||
`n${oper.element}`,
|
`n${oper.element}`,
|
||||||
name,
|
name,
|
||||||
|
|
|
@ -9,13 +9,10 @@ import {
|
||||||
walkIdentifiers,
|
walkIdentifiers,
|
||||||
} from '@vue/compiler-dom'
|
} from '@vue/compiler-dom'
|
||||||
import type { Identifier } from '@babel/types'
|
import type { Identifier } from '@babel/types'
|
||||||
import {
|
import type { CodegenContext } from '../generate'
|
||||||
type CodeFragment,
|
|
||||||
type CodegenContext,
|
|
||||||
buildCodeFragment,
|
|
||||||
} from '../generate'
|
|
||||||
import type { Node } from '@babel/types'
|
import type { Node } from '@babel/types'
|
||||||
import { isConstantExpression } from '../utils'
|
import { isConstantExpression } from '../utils'
|
||||||
|
import { type CodeFragment, buildCodeFragment } from './utils'
|
||||||
|
|
||||||
export function genExpression(
|
export function genExpression(
|
||||||
node: SimpleExpressionNode,
|
node: SimpleExpressionNode,
|
||||||
|
|
|
@ -1,22 +1,23 @@
|
||||||
|
import { NewlineType } from '@vue/compiler-dom'
|
||||||
import { genBlockFunction } from './block'
|
import { genBlockFunction } from './block'
|
||||||
import { genExpression } from './expression'
|
import { genExpression } from './expression'
|
||||||
|
import type { CodegenContext } from '../generate'
|
||||||
|
import type { ForIRNode, IREffect } from '../ir'
|
||||||
|
import { genOperation } from './operation'
|
||||||
import {
|
import {
|
||||||
type CodeFragment,
|
type CodeFragment,
|
||||||
type CodegenContext,
|
|
||||||
INDENT_END,
|
INDENT_END,
|
||||||
INDENT_START,
|
INDENT_START,
|
||||||
NEWLINE,
|
NEWLINE,
|
||||||
buildCodeFragment,
|
buildCodeFragment,
|
||||||
} from '../generate'
|
genCall,
|
||||||
import type { ForIRNode, IREffect } from '../ir'
|
} from './utils'
|
||||||
import { genOperation } from './operation'
|
|
||||||
import { NewlineType } from '@vue/compiler-dom'
|
|
||||||
|
|
||||||
export function genFor(
|
export function genFor(
|
||||||
oper: ForIRNode,
|
oper: ForIRNode,
|
||||||
context: CodegenContext,
|
context: CodegenContext,
|
||||||
): CodeFragment[] {
|
): CodeFragment[] {
|
||||||
const { call, vaporHelper } = context
|
const { vaporHelper } = context
|
||||||
const { source, value, key, render, keyProperty } = oper
|
const { source, value, key, render, keyProperty } = oper
|
||||||
|
|
||||||
const rawValue = value && value.content
|
const rawValue = value && value.content
|
||||||
|
@ -58,7 +59,7 @@ export function genFor(
|
||||||
return [
|
return [
|
||||||
NEWLINE,
|
NEWLINE,
|
||||||
`const n${oper.id} = `,
|
`const n${oper.id} = `,
|
||||||
...call(vaporHelper('createFor'), sourceExpr, blockFn, getKeyFn),
|
...genCall(vaporHelper('createFor'), sourceExpr, blockFn, getKeyFn),
|
||||||
]
|
]
|
||||||
|
|
||||||
function genEffectInFor(effects: IREffect[]): CodeFragment[] {
|
function genEffectInFor(effects: IREffect[]): CodeFragment[] {
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
import { type CodeFragment, type CodegenContext, NEWLINE } from '../generate'
|
import type { CodegenContext } from '../generate'
|
||||||
import type { SetHtmlIRNode } from '../ir'
|
import type { SetHtmlIRNode } from '../ir'
|
||||||
import { genExpression } from './expression'
|
import { genExpression } from './expression'
|
||||||
|
import { type CodeFragment, NEWLINE, genCall } from './utils'
|
||||||
|
|
||||||
export function genSetHtml(
|
export function genSetHtml(
|
||||||
oper: SetHtmlIRNode,
|
oper: SetHtmlIRNode,
|
||||||
context: CodegenContext,
|
context: CodegenContext,
|
||||||
): CodeFragment[] {
|
): CodeFragment[] {
|
||||||
const { call, vaporHelper } = context
|
const { vaporHelper } = context
|
||||||
return [
|
return [
|
||||||
NEWLINE,
|
NEWLINE,
|
||||||
...call(
|
...genCall(
|
||||||
vaporHelper('setHtml'),
|
vaporHelper('setHtml'),
|
||||||
`n${oper.element}`,
|
`n${oper.element}`,
|
||||||
genExpression(oper.value, context),
|
genExpression(oper.value, context),
|
||||||
|
|
|
@ -1,19 +1,15 @@
|
||||||
import {
|
import type { CodegenContext } from '../generate'
|
||||||
type CodeFragment,
|
|
||||||
type CodegenContext,
|
|
||||||
NEWLINE,
|
|
||||||
buildCodeFragment,
|
|
||||||
} from '../generate'
|
|
||||||
import { IRNodeTypes, type IfIRNode } from '../ir'
|
import { IRNodeTypes, type IfIRNode } from '../ir'
|
||||||
import { genBlockFunction } from './block'
|
import { genBlockFunction } from './block'
|
||||||
import { genExpression } from './expression'
|
import { genExpression } from './expression'
|
||||||
|
import { type CodeFragment, NEWLINE, buildCodeFragment, genCall } from './utils'
|
||||||
|
|
||||||
export function genIf(
|
export function genIf(
|
||||||
oper: IfIRNode,
|
oper: IfIRNode,
|
||||||
context: CodegenContext,
|
context: CodegenContext,
|
||||||
isNested = false,
|
isNested = false,
|
||||||
): CodeFragment[] {
|
): CodeFragment[] {
|
||||||
const { call, vaporHelper } = context
|
const { vaporHelper } = context
|
||||||
const { condition, positive, negative } = oper
|
const { condition, positive, negative } = oper
|
||||||
const [frag, push] = buildCodeFragment()
|
const [frag, push] = buildCodeFragment()
|
||||||
|
|
||||||
|
@ -36,7 +32,12 @@ export function genIf(
|
||||||
|
|
||||||
if (!isNested) push(NEWLINE, `const n${oper.id} = `)
|
if (!isNested) push(NEWLINE, `const n${oper.id} = `)
|
||||||
push(
|
push(
|
||||||
...call(vaporHelper('createIf'), conditionExpr, positiveArg, negativeArg),
|
...genCall(
|
||||||
|
vaporHelper('createIf'),
|
||||||
|
conditionExpr,
|
||||||
|
positiveArg,
|
||||||
|
negativeArg,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return frag
|
return frag
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { camelize } from '@vue/shared'
|
import { camelize } from '@vue/shared'
|
||||||
import { genExpression } from './expression'
|
import { genExpression } from './expression'
|
||||||
import type { SetModelValueIRNode } from '../ir'
|
import type { SetModelValueIRNode } from '../ir'
|
||||||
import { type CodeFragment, type CodegenContext, NEWLINE } from '../generate'
|
import type { CodegenContext } from '../generate'
|
||||||
|
import { type CodeFragment, NEWLINE, genCall } from './utils'
|
||||||
|
|
||||||
export function genSetModelValue(
|
export function genSetModelValue(
|
||||||
oper: SetModelValueIRNode,
|
oper: SetModelValueIRNode,
|
||||||
|
@ -9,7 +10,7 @@ export function genSetModelValue(
|
||||||
): CodeFragment[] {
|
): CodeFragment[] {
|
||||||
const {
|
const {
|
||||||
vaporHelper,
|
vaporHelper,
|
||||||
call,
|
|
||||||
options: { isTS },
|
options: { isTS },
|
||||||
} = context
|
} = context
|
||||||
|
|
||||||
|
@ -24,6 +25,6 @@ export function genSetModelValue(
|
||||||
|
|
||||||
return [
|
return [
|
||||||
NEWLINE,
|
NEWLINE,
|
||||||
...call(vaporHelper('on'), `n${oper.element}`, name, handler),
|
...genCall(vaporHelper('on'), `n${oper.element}`, name, handler),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,5 @@
|
||||||
import { type IREffect, IRNodeTypes, type OperationNode } from '../ir'
|
import { type IREffect, IRNodeTypes, type OperationNode } from '../ir'
|
||||||
import {
|
import type { CodegenContext } from '../generate'
|
||||||
type CodeFragment,
|
|
||||||
type CodegenContext,
|
|
||||||
INDENT_END,
|
|
||||||
INDENT_START,
|
|
||||||
NEWLINE,
|
|
||||||
buildCodeFragment,
|
|
||||||
} from '../generate'
|
|
||||||
import { genAppendNode, genInsertNode, genPrependNode } from './dom'
|
import { genAppendNode, genInsertNode, genPrependNode } from './dom'
|
||||||
import { genSetEvent } from './event'
|
import { genSetEvent } from './event'
|
||||||
import { genFor } from './for'
|
import { genFor } from './for'
|
||||||
|
@ -16,6 +9,13 @@ import { genSetModelValue } from './modelValue'
|
||||||
import { genDynamicProps, genSetProp } from './prop'
|
import { genDynamicProps, genSetProp } from './prop'
|
||||||
import { genSetRef } from './ref'
|
import { genSetRef } from './ref'
|
||||||
import { genCreateTextNode, genSetText } from './text'
|
import { genCreateTextNode, genSetText } from './text'
|
||||||
|
import {
|
||||||
|
type CodeFragment,
|
||||||
|
INDENT_END,
|
||||||
|
INDENT_START,
|
||||||
|
NEWLINE,
|
||||||
|
buildCodeFragment,
|
||||||
|
} from './utils'
|
||||||
|
|
||||||
export function genOperations(opers: OperationNode[], context: CodegenContext) {
|
export function genOperations(opers: OperationNode[], context: CodegenContext) {
|
||||||
const [frag, push] = buildCodeFragment()
|
const [frag, push] = buildCodeFragment()
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {
|
||||||
type SimpleExpressionNode,
|
type SimpleExpressionNode,
|
||||||
isSimpleIdentifier,
|
isSimpleIdentifier,
|
||||||
} from '@vue/compiler-core'
|
} from '@vue/compiler-core'
|
||||||
import { type CodeFragment, type CodegenContext, NEWLINE } from '../generate'
|
import type { CodegenContext } from '../generate'
|
||||||
import type {
|
import type {
|
||||||
IRProp,
|
IRProp,
|
||||||
SetDynamicPropsIRNode,
|
SetDynamicPropsIRNode,
|
||||||
|
@ -11,13 +11,14 @@ import type {
|
||||||
VaporHelper,
|
VaporHelper,
|
||||||
} from '../ir'
|
} from '../ir'
|
||||||
import { genExpression } from './expression'
|
import { genExpression } from './expression'
|
||||||
|
import { type CodeFragment, NEWLINE, genCall, genMulti } from './utils'
|
||||||
|
|
||||||
// only the static key prop will reach here
|
// only the static key prop will reach here
|
||||||
export function genSetProp(
|
export function genSetProp(
|
||||||
oper: SetPropIRNode,
|
oper: SetPropIRNode,
|
||||||
context: CodegenContext,
|
context: CodegenContext,
|
||||||
): CodeFragment[] {
|
): CodeFragment[] {
|
||||||
const { call, vaporHelper } = context
|
const { vaporHelper } = context
|
||||||
const {
|
const {
|
||||||
prop: { key, values, modifier },
|
prop: { key, values, modifier },
|
||||||
} = oper
|
} = oper
|
||||||
|
@ -40,7 +41,7 @@ export function genSetProp(
|
||||||
|
|
||||||
return [
|
return [
|
||||||
NEWLINE,
|
NEWLINE,
|
||||||
...call(
|
...genCall(
|
||||||
vaporHelper(helperName),
|
vaporHelper(helperName),
|
||||||
`n${oper.element}`,
|
`n${oper.element}`,
|
||||||
omitKey ? false : genExpression(key, context),
|
omitKey ? false : genExpression(key, context),
|
||||||
|
@ -54,10 +55,10 @@ export function genDynamicProps(
|
||||||
oper: SetDynamicPropsIRNode,
|
oper: SetDynamicPropsIRNode,
|
||||||
context: CodegenContext,
|
context: CodegenContext,
|
||||||
): CodeFragment[] {
|
): CodeFragment[] {
|
||||||
const { call, vaporHelper } = context
|
const { vaporHelper } = context
|
||||||
return [
|
return [
|
||||||
NEWLINE,
|
NEWLINE,
|
||||||
...call(
|
...genCall(
|
||||||
vaporHelper('setDynamicProps'),
|
vaporHelper('setDynamicProps'),
|
||||||
`n${oper.element}`,
|
`n${oper.element}`,
|
||||||
...oper.props.map(
|
...oper.props.map(
|
||||||
|
@ -74,8 +75,7 @@ function genLiteralObjectProps(
|
||||||
props: IRProp[],
|
props: IRProp[],
|
||||||
context: CodegenContext,
|
context: CodegenContext,
|
||||||
): CodeFragment[] {
|
): CodeFragment[] {
|
||||||
const { multi } = context
|
return genMulti(
|
||||||
return multi(
|
|
||||||
['{ ', ' }', ', '],
|
['{ ', ' }', ', '],
|
||||||
...props.map(prop => [
|
...props.map(prop => [
|
||||||
...genPropertyKey(prop, context),
|
...genPropertyKey(prop, context),
|
||||||
|
@ -89,7 +89,7 @@ function genPropertyKey(
|
||||||
{ key: node, runtimeCamelize, modifier }: IRProp,
|
{ key: node, runtimeCamelize, modifier }: IRProp,
|
||||||
context: CodegenContext,
|
context: CodegenContext,
|
||||||
): CodeFragment[] {
|
): CodeFragment[] {
|
||||||
const { call, helper } = context
|
const { helper } = context
|
||||||
|
|
||||||
// static arg was transformed by v-bind transformer
|
// static arg was transformed by v-bind transformer
|
||||||
if (node.isStatic) {
|
if (node.isStatic) {
|
||||||
|
@ -108,7 +108,7 @@ function genPropertyKey(
|
||||||
return [
|
return [
|
||||||
'[',
|
'[',
|
||||||
modifier && `${JSON.stringify(modifier)} + `,
|
modifier && `${JSON.stringify(modifier)} + `,
|
||||||
...(runtimeCamelize ? call(helper('camelize'), key) : key),
|
...(runtimeCamelize ? genCall(helper('camelize'), key) : key),
|
||||||
']',
|
']',
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -117,8 +117,7 @@ function genPropValue(values: SimpleExpressionNode[], context: CodegenContext) {
|
||||||
if (values.length === 1) {
|
if (values.length === 1) {
|
||||||
return genExpression(values[0], context)
|
return genExpression(values[0], context)
|
||||||
}
|
}
|
||||||
const { multi } = context
|
return genMulti(
|
||||||
return multi(
|
|
||||||
['[', ']', ', '],
|
['[', ']', ', '],
|
||||||
...values.map(expr => genExpression(expr, context)),
|
...values.map(expr => genExpression(expr, context)),
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
import { genExpression } from './expression'
|
import { genExpression } from './expression'
|
||||||
import { type CodeFragment, type CodegenContext, NEWLINE } from '../generate'
|
import type { CodegenContext } from '../generate'
|
||||||
import type { SetRefIRNode } from '../ir'
|
import type { SetRefIRNode } from '../ir'
|
||||||
|
import { type CodeFragment, NEWLINE, genCall } from './utils'
|
||||||
|
|
||||||
export function genSetRef(
|
export function genSetRef(
|
||||||
oper: SetRefIRNode,
|
oper: SetRefIRNode,
|
||||||
context: CodegenContext,
|
context: CodegenContext,
|
||||||
): CodeFragment[] {
|
): CodeFragment[] {
|
||||||
const { call, vaporHelper } = context
|
const { vaporHelper } = context
|
||||||
return [
|
return [
|
||||||
NEWLINE,
|
NEWLINE,
|
||||||
...call(
|
...genCall(
|
||||||
vaporHelper('setRef'),
|
vaporHelper('setRef'),
|
||||||
[`n${oper.element}`],
|
[`n${oper.element}`],
|
||||||
genExpression(oper.value, context),
|
genExpression(oper.value, context),
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { type CodegenContext, NEWLINE, buildCodeFragment } from '../generate'
|
import type { CodegenContext } from '../generate'
|
||||||
import {
|
import {
|
||||||
DynamicFlag,
|
DynamicFlag,
|
||||||
type IRDynamicInfo,
|
type IRDynamicInfo,
|
||||||
type TemplateFactoryIRNode,
|
type TemplateFactoryIRNode,
|
||||||
} from '../ir'
|
} from '../ir'
|
||||||
|
import { NEWLINE, buildCodeFragment, genCall } from './utils'
|
||||||
|
|
||||||
export function genTemplates(
|
export function genTemplates(
|
||||||
templates: TemplateFactoryIRNode[],
|
templates: TemplateFactoryIRNode[],
|
||||||
|
@ -23,7 +24,7 @@ export function genChildren(
|
||||||
from: number,
|
from: number,
|
||||||
paths: number[] = [],
|
paths: number[] = [],
|
||||||
) {
|
) {
|
||||||
const { vaporHelper, call } = context
|
const { vaporHelper } = context
|
||||||
const [frag, push] = buildCodeFragment()
|
const [frag, push] = buildCodeFragment()
|
||||||
let offset = 0
|
let offset = 0
|
||||||
const { children } = dynamic
|
const { children } = dynamic
|
||||||
|
@ -47,7 +48,11 @@ export function genChildren(
|
||||||
push(
|
push(
|
||||||
NEWLINE,
|
NEWLINE,
|
||||||
`const n${id} = `,
|
`const n${id} = `,
|
||||||
...call(vaporHelper('children'), `n${from}`, ...newPaths.map(String)),
|
...genCall(
|
||||||
|
vaporHelper('children'),
|
||||||
|
`n${from}`,
|
||||||
|
...newPaths.map(String),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
push(...genChildren(child, context, id, []))
|
push(...genChildren(child, context, id, []))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
import { type CodeFragment, type CodegenContext, NEWLINE } from '../generate'
|
import type { CodegenContext } from '../generate'
|
||||||
import type { CreateTextNodeIRNode, SetTextIRNode } from '../ir'
|
import type { CreateTextNodeIRNode, SetTextIRNode } from '../ir'
|
||||||
import { genExpression } from './expression'
|
import { genExpression } from './expression'
|
||||||
|
import { type CodeFragment, NEWLINE, genCall } from './utils'
|
||||||
|
|
||||||
export function genSetText(
|
export function genSetText(
|
||||||
oper: SetTextIRNode,
|
oper: SetTextIRNode,
|
||||||
context: CodegenContext,
|
context: CodegenContext,
|
||||||
): CodeFragment[] {
|
): CodeFragment[] {
|
||||||
const { call, vaporHelper } = context
|
const { vaporHelper } = context
|
||||||
const { values } = oper
|
const { values } = oper
|
||||||
return [
|
return [
|
||||||
NEWLINE,
|
NEWLINE,
|
||||||
...call(
|
...genCall(
|
||||||
vaporHelper('setText'),
|
vaporHelper('setText'),
|
||||||
`n${oper.element}`,
|
`n${oper.element}`,
|
||||||
...values.map(value => genExpression(value, context)),
|
...values.map(value => genExpression(value, context)),
|
||||||
|
@ -22,10 +23,10 @@ export function genCreateTextNode(
|
||||||
oper: CreateTextNodeIRNode,
|
oper: CreateTextNodeIRNode,
|
||||||
context: CodegenContext,
|
context: CodegenContext,
|
||||||
): CodeFragment[] {
|
): CodeFragment[] {
|
||||||
const { call, vaporHelper } = context
|
const { vaporHelper } = context
|
||||||
return [
|
return [
|
||||||
NEWLINE,
|
NEWLINE,
|
||||||
`const n${oper.id} = `,
|
`const n${oper.id} = `,
|
||||||
...call(vaporHelper('createTextNode')),
|
...genCall(vaporHelper('createTextNode')),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
import {
|
||||||
|
NewlineType,
|
||||||
|
type Position,
|
||||||
|
type SourceLocation,
|
||||||
|
advancePositionWithMutation,
|
||||||
|
locStub,
|
||||||
|
} from '@vue/compiler-dom'
|
||||||
|
import { isArray, isString } from '@vue/shared'
|
||||||
|
import type { CodegenContext } from '../generate'
|
||||||
|
|
||||||
|
export const NEWLINE = Symbol(__DEV__ ? `newline` : ``)
|
||||||
|
/** increase offset but don't push actual code */
|
||||||
|
export const LF = Symbol(__DEV__ ? `line feed` : ``)
|
||||||
|
export const INDENT_START = Symbol(__DEV__ ? `indent start` : ``)
|
||||||
|
export const INDENT_END = Symbol(__DEV__ ? `indent end` : ``)
|
||||||
|
|
||||||
|
type FalsyValue = false | null | undefined
|
||||||
|
export type CodeFragment =
|
||||||
|
| typeof NEWLINE
|
||||||
|
| typeof LF
|
||||||
|
| typeof INDENT_START
|
||||||
|
| typeof INDENT_END
|
||||||
|
| string
|
||||||
|
| [code: string, newlineIndex?: number, loc?: SourceLocation, name?: string]
|
||||||
|
| FalsyValue
|
||||||
|
export type CodeFragments = Exclude<CodeFragment, any[]> | CodeFragment[]
|
||||||
|
|
||||||
|
export function buildCodeFragment(...frag: CodeFragment[]) {
|
||||||
|
const push = frag.push.bind(frag)
|
||||||
|
return [frag, push] as const
|
||||||
|
}
|
||||||
|
|
||||||
|
export function genMulti(
|
||||||
|
[left, right, seg]: [
|
||||||
|
left: CodeFragment,
|
||||||
|
right: CodeFragment,
|
||||||
|
segment: CodeFragment,
|
||||||
|
],
|
||||||
|
...fns: CodeFragments[]
|
||||||
|
): CodeFragment[] {
|
||||||
|
const frag: CodeFragment[] = []
|
||||||
|
fns = fns.filter(Boolean)
|
||||||
|
frag.push(left)
|
||||||
|
for (let [i, fn] of (
|
||||||
|
fns as Array<Exclude<CodeFragments, FalsyValue>>
|
||||||
|
).entries()) {
|
||||||
|
if (!isArray(fn)) fn = [fn]
|
||||||
|
frag.push(...fn)
|
||||||
|
if (i < fns.length - 1) frag.push(seg)
|
||||||
|
}
|
||||||
|
frag.push(right)
|
||||||
|
return frag
|
||||||
|
}
|
||||||
|
|
||||||
|
export function genCall(
|
||||||
|
name: string,
|
||||||
|
...args: CodeFragments[]
|
||||||
|
): CodeFragment[] {
|
||||||
|
return [name, ...genMulti(['(', ')', ', '], ...args)]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function genCodeFragment(context: CodegenContext) {
|
||||||
|
let codegen = ''
|
||||||
|
const pos = { line: 1, column: 1, offset: 0 }
|
||||||
|
let indentLevel = 0
|
||||||
|
|
||||||
|
for (let frag of context.code) {
|
||||||
|
if (!frag) continue
|
||||||
|
|
||||||
|
if (frag === NEWLINE) {
|
||||||
|
frag = [`\n${` `.repeat(indentLevel)}`, NewlineType.Start]
|
||||||
|
} else if (frag === INDENT_START) {
|
||||||
|
indentLevel++
|
||||||
|
continue
|
||||||
|
} else if (frag === INDENT_END) {
|
||||||
|
indentLevel--
|
||||||
|
continue
|
||||||
|
} else if (frag === LF) {
|
||||||
|
pos.line++
|
||||||
|
pos.column = 0
|
||||||
|
pos.offset++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isString(frag)) frag = [frag]
|
||||||
|
|
||||||
|
let [code, newlineIndex = NewlineType.None, loc, name] = frag
|
||||||
|
codegen += code
|
||||||
|
|
||||||
|
if (!__BROWSER__ && context.map) {
|
||||||
|
if (loc) addMapping(loc.start, name)
|
||||||
|
if (newlineIndex === NewlineType.Unknown) {
|
||||||
|
// multiple newlines, full iteration
|
||||||
|
advancePositionWithMutation(pos, code)
|
||||||
|
} else {
|
||||||
|
// fast paths
|
||||||
|
pos.offset += code.length
|
||||||
|
if (newlineIndex === NewlineType.None) {
|
||||||
|
// no newlines; fast path to avoid newline detection
|
||||||
|
if (__TEST__ && code.includes('\n')) {
|
||||||
|
throw new Error(
|
||||||
|
`CodegenContext.push() called newlineIndex: none, but contains` +
|
||||||
|
`newlines: ${code.replace(/\n/g, '\\n')}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pos.column += code.length
|
||||||
|
} else {
|
||||||
|
// single newline at known index
|
||||||
|
if (newlineIndex === NewlineType.End) {
|
||||||
|
newlineIndex = code.length - 1
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
__TEST__ &&
|
||||||
|
(code.charAt(newlineIndex) !== '\n' ||
|
||||||
|
code.slice(0, newlineIndex).includes('\n') ||
|
||||||
|
code.slice(newlineIndex + 1).includes('\n'))
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
`CodegenContext.push() called with newlineIndex: ${newlineIndex} ` +
|
||||||
|
`but does not conform: ${code.replace(/\n/g, '\\n')}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pos.line++
|
||||||
|
pos.column = code.length - newlineIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (loc && loc !== locStub) {
|
||||||
|
addMapping(loc.end)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return codegen
|
||||||
|
|
||||||
|
function addMapping(loc: Position, name: string | null = null) {
|
||||||
|
// we use the private property to directly add the mapping
|
||||||
|
// because the addMapping() implementation in source-map-js has a bunch of
|
||||||
|
// unnecessary arg and validation checks that are pure overhead in our case.
|
||||||
|
const { _names, _mappings } = context.map!
|
||||||
|
if (name !== null && !_names.has(name)) _names.add(name)
|
||||||
|
_mappings.add({
|
||||||
|
originalLine: loc.line,
|
||||||
|
originalColumn: loc.column - 1, // source-map column is 0 based
|
||||||
|
generatedLine: pos.line,
|
||||||
|
generatedColumn: pos.column - 1,
|
||||||
|
source: context.options.filename,
|
||||||
|
// @ts-expect-error it is possible to be null
|
||||||
|
name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,12 @@
|
||||||
export { parse } from '@vue/compiler-dom'
|
export { parse } from '@vue/compiler-dom'
|
||||||
export { transform } from './transform'
|
export * from './transform'
|
||||||
export { generate } from './generate'
|
export * from './generate'
|
||||||
export { compile, type CompilerOptions } from './compile'
|
export {
|
||||||
|
wrapTemplate,
|
||||||
|
compile,
|
||||||
|
type CompilerOptions,
|
||||||
|
type TransformPreset,
|
||||||
|
} from './compile'
|
||||||
export * from './ir'
|
export * from './ir'
|
||||||
export * from './errors'
|
export * from './errors'
|
||||||
export { transformElement } from './transforms/transformElement'
|
export { transformElement } from './transforms/transformElement'
|
||||||
|
|
|
@ -1,17 +1,13 @@
|
||||||
import {
|
import {
|
||||||
type AllNode,
|
type AllNode,
|
||||||
type AttributeNode,
|
|
||||||
type TransformOptions as BaseTransformOptions,
|
type TransformOptions as BaseTransformOptions,
|
||||||
type CompilerCompatOptions,
|
type CompilerCompatOptions,
|
||||||
type DirectiveNode,
|
|
||||||
type ElementNode,
|
type ElementNode,
|
||||||
ElementTypes,
|
ElementTypes,
|
||||||
NodeTypes,
|
NodeTypes,
|
||||||
type RootNode,
|
type RootNode,
|
||||||
type SimpleExpressionNode,
|
type SimpleExpressionNode,
|
||||||
type TemplateChildNode,
|
type TemplateChildNode,
|
||||||
type TemplateNode,
|
|
||||||
createSimpleExpression,
|
|
||||||
defaultOnError,
|
defaultOnError,
|
||||||
defaultOnWarn,
|
defaultOnWarn,
|
||||||
isVSlot,
|
isVSlot,
|
||||||
|
@ -28,6 +24,7 @@ import {
|
||||||
type VaporDirectiveNode,
|
type VaporDirectiveNode,
|
||||||
} from './ir'
|
} from './ir'
|
||||||
import { isConstantExpression } from './utils'
|
import { isConstantExpression } from './utils'
|
||||||
|
import { genDefaultDynamic } from './transforms/utils'
|
||||||
|
|
||||||
export type NodeTransform = (
|
export type NodeTransform = (
|
||||||
node: RootNode | TemplateChildNode,
|
node: RootNode | TemplateChildNode,
|
||||||
|
@ -108,13 +105,6 @@ const defaultOptions = {
|
||||||
onWarn: defaultOnWarn,
|
onWarn: defaultOnWarn,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const genDefaultDynamic = (): IRDynamicInfo => ({
|
|
||||||
id: null,
|
|
||||||
flags: DynamicFlag.NONE,
|
|
||||||
anchor: null,
|
|
||||||
children: [],
|
|
||||||
})
|
|
||||||
|
|
||||||
// TODO use class for better perf
|
// TODO use class for better perf
|
||||||
function createRootContext(
|
function createRootContext(
|
||||||
root: RootIRNode,
|
root: RootIRNode,
|
||||||
|
@ -411,29 +401,3 @@ export function createStructuralDirectiveTransform(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function wrapTemplate(node: ElementNode, dirs: string[]): TemplateNode {
|
|
||||||
if (node.tagType === ElementTypes.TEMPLATE) {
|
|
||||||
return node
|
|
||||||
}
|
|
||||||
|
|
||||||
const reserved: Array<AttributeNode | DirectiveNode> = []
|
|
||||||
const pass: Array<AttributeNode | DirectiveNode> = []
|
|
||||||
node.props.forEach(prop => {
|
|
||||||
if (prop.type === NodeTypes.DIRECTIVE && dirs.includes(prop.name)) {
|
|
||||||
reserved.push(prop)
|
|
||||||
} else {
|
|
||||||
pass.push(prop)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return extend({}, node, {
|
|
||||||
type: NodeTypes.ELEMENT,
|
|
||||||
tag: 'template',
|
|
||||||
props: reserved,
|
|
||||||
tagType: ElementTypes.TEMPLATE,
|
|
||||||
children: [extend({}, node, { props: pass } as TemplateChildNode)],
|
|
||||||
} as Partial<TemplateNode>)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const EMPTY_EXPRESSION = createSimpleExpression('', true)
|
|
||||||
|
|
|
@ -14,11 +14,10 @@ import {
|
||||||
isReservedProp,
|
isReservedProp,
|
||||||
isVoidTag,
|
isVoidTag,
|
||||||
} from '@vue/shared'
|
} from '@vue/shared'
|
||||||
import {
|
import type {
|
||||||
type DirectiveTransformResult,
|
DirectiveTransformResult,
|
||||||
EMPTY_EXPRESSION,
|
NodeTransform,
|
||||||
type NodeTransform,
|
TransformContext,
|
||||||
type TransformContext,
|
|
||||||
} from '../transform'
|
} from '../transform'
|
||||||
import {
|
import {
|
||||||
IRNodeTypes,
|
IRNodeTypes,
|
||||||
|
@ -26,6 +25,7 @@ import {
|
||||||
type IRProps,
|
type IRProps,
|
||||||
type VaporDirectiveNode,
|
type VaporDirectiveNode,
|
||||||
} from '../ir'
|
} from '../ir'
|
||||||
|
import { EMPTY_EXPRESSION } from './utils'
|
||||||
|
|
||||||
export const transformElement: NodeTransform = (node, context) => {
|
export const transformElement: NodeTransform = (node, context) => {
|
||||||
return function postTransformElement() {
|
return function postTransformElement() {
|
||||||
|
|
|
@ -3,10 +3,11 @@ import {
|
||||||
type SimpleExpressionNode,
|
type SimpleExpressionNode,
|
||||||
createSimpleExpression,
|
createSimpleExpression,
|
||||||
} from '@vue/compiler-dom'
|
} from '@vue/compiler-dom'
|
||||||
import { EMPTY_EXPRESSION, type NodeTransform } from '../transform'
|
import type { NodeTransform } from '../transform'
|
||||||
import { IRNodeTypes } from '../ir'
|
import { IRNodeTypes } from '../ir'
|
||||||
import { normalizeBindShorthand } from './vBind'
|
import { normalizeBindShorthand } from './vBind'
|
||||||
import { findProp } from '../utils'
|
import { findProp } from '../utils'
|
||||||
|
import { EMPTY_EXPRESSION } from './utils'
|
||||||
|
|
||||||
export const transformRef: NodeTransform = (node, context) => {
|
export const transformRef: NodeTransform = (node, context) => {
|
||||||
if (node.type !== NodeTypes.ELEMENT) return
|
if (node.type !== NodeTypes.ELEMENT) return
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
import {
|
||||||
|
type AttributeNode,
|
||||||
|
type DirectiveNode,
|
||||||
|
type ElementNode,
|
||||||
|
ElementTypes,
|
||||||
|
NodeTypes,
|
||||||
|
type TemplateChildNode,
|
||||||
|
type TemplateNode,
|
||||||
|
createSimpleExpression,
|
||||||
|
} from '@vue/compiler-dom'
|
||||||
|
import { extend } from '@vue/shared'
|
||||||
|
import { DynamicFlag, type IRDynamicInfo } from '../ir'
|
||||||
|
|
||||||
|
export const genDefaultDynamic = (): IRDynamicInfo => ({
|
||||||
|
id: null,
|
||||||
|
flags: DynamicFlag.NONE,
|
||||||
|
anchor: null,
|
||||||
|
children: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
export function wrapTemplate(node: ElementNode, dirs: string[]): TemplateNode {
|
||||||
|
if (node.tagType === ElementTypes.TEMPLATE) {
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
const reserved: Array<AttributeNode | DirectiveNode> = []
|
||||||
|
const pass: Array<AttributeNode | DirectiveNode> = []
|
||||||
|
node.props.forEach(prop => {
|
||||||
|
if (prop.type === NodeTypes.DIRECTIVE && dirs.includes(prop.name)) {
|
||||||
|
reserved.push(prop)
|
||||||
|
} else {
|
||||||
|
pass.push(prop)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return extend({}, node, {
|
||||||
|
type: NodeTypes.ELEMENT,
|
||||||
|
tag: 'template',
|
||||||
|
props: reserved,
|
||||||
|
tagType: ElementTypes.TEMPLATE,
|
||||||
|
children: [extend({}, node, { props: pass } as TemplateChildNode)],
|
||||||
|
} as Partial<TemplateNode>)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const EMPTY_EXPRESSION = createSimpleExpression('', true)
|
|
@ -7,8 +7,6 @@ import {
|
||||||
import {
|
import {
|
||||||
type TransformContext,
|
type TransformContext,
|
||||||
createStructuralDirectiveTransform,
|
createStructuralDirectiveTransform,
|
||||||
genDefaultDynamic,
|
|
||||||
wrapTemplate,
|
|
||||||
} from '../transform'
|
} from '../transform'
|
||||||
import {
|
import {
|
||||||
type BlockFunctionIRNode,
|
type BlockFunctionIRNode,
|
||||||
|
@ -19,6 +17,7 @@ import {
|
||||||
} from '../ir'
|
} from '../ir'
|
||||||
import { extend } from '@vue/shared'
|
import { extend } from '@vue/shared'
|
||||||
import { findProp, propToExpression } from '../utils'
|
import { findProp, propToExpression } from '../utils'
|
||||||
|
import { genDefaultDynamic, wrapTemplate } from './utils'
|
||||||
|
|
||||||
export const transformVFor = createStructuralDirectiveTransform(
|
export const transformVFor = createStructuralDirectiveTransform(
|
||||||
'for',
|
'for',
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { IRNodeTypes } from '../ir'
|
import { IRNodeTypes } from '../ir'
|
||||||
import { type DirectiveTransform, EMPTY_EXPRESSION } from '../transform'
|
import type { DirectiveTransform } from '../transform'
|
||||||
import { DOMErrorCodes, createDOMCompilerError } from '@vue/compiler-dom'
|
import { DOMErrorCodes, createDOMCompilerError } from '@vue/compiler-dom'
|
||||||
|
import { EMPTY_EXPRESSION } from './utils'
|
||||||
|
|
||||||
export const transformVHtml: DirectiveTransform = (dir, node, context) => {
|
export const transformVHtml: DirectiveTransform = (dir, node, context) => {
|
||||||
let { exp, loc } = dir
|
let { exp, loc } = dir
|
||||||
|
|
|
@ -9,8 +9,6 @@ import {
|
||||||
import {
|
import {
|
||||||
type TransformContext,
|
type TransformContext,
|
||||||
createStructuralDirectiveTransform,
|
createStructuralDirectiveTransform,
|
||||||
genDefaultDynamic,
|
|
||||||
wrapTemplate,
|
|
||||||
} from '../transform'
|
} from '../transform'
|
||||||
import {
|
import {
|
||||||
type BlockFunctionIRNode,
|
type BlockFunctionIRNode,
|
||||||
|
@ -21,6 +19,7 @@ import {
|
||||||
type VaporDirectiveNode,
|
type VaporDirectiveNode,
|
||||||
} from '../ir'
|
} from '../ir'
|
||||||
import { extend } from '@vue/shared'
|
import { extend } from '@vue/shared'
|
||||||
|
import { genDefaultDynamic, wrapTemplate } from './utils'
|
||||||
|
|
||||||
export const transformVIf = createStructuralDirectiveTransform(
|
export const transformVIf = createStructuralDirectiveTransform(
|
||||||
['if', 'else', 'else-if'],
|
['if', 'else', 'else-if'],
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { DOMErrorCodes, createDOMCompilerError } from '@vue/compiler-dom'
|
import { DOMErrorCodes, createDOMCompilerError } from '@vue/compiler-dom'
|
||||||
import { type DirectiveTransform, EMPTY_EXPRESSION } from '../transform'
|
|
||||||
import { IRNodeTypes } from '../ir'
|
import { IRNodeTypes } from '../ir'
|
||||||
|
import { EMPTY_EXPRESSION } from './utils'
|
||||||
|
import type { DirectiveTransform } from '../transform'
|
||||||
|
|
||||||
export const transformVText: DirectiveTransform = (dir, node, context) => {
|
export const transformVText: DirectiveTransform = (dir, node, context) => {
|
||||||
let { exp, loc } = dir
|
let { exp, loc } = dir
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import type { NumericLiteral, StringLiteral } from '@babel/types'
|
||||||
import { isGloballyAllowed } from '@vue/shared'
|
import { isGloballyAllowed } from '@vue/shared'
|
||||||
import {
|
import {
|
||||||
type AttributeNode,
|
type AttributeNode,
|
||||||
|
@ -9,8 +10,7 @@ import {
|
||||||
isLiteralWhitelisted,
|
isLiteralWhitelisted,
|
||||||
} from '@vue/compiler-dom'
|
} from '@vue/compiler-dom'
|
||||||
import type { VaporDirectiveNode } from './ir'
|
import type { VaporDirectiveNode } from './ir'
|
||||||
import { EMPTY_EXPRESSION } from './transform'
|
import { EMPTY_EXPRESSION } from './transforms/utils'
|
||||||
import type { NumericLiteral, StringLiteral } from '@babel/types'
|
|
||||||
|
|
||||||
export const findProp = _findProp as (
|
export const findProp = _findProp as (
|
||||||
node: ElementNode,
|
node: ElementNode,
|
||||||
|
|
Loading…
Reference in New Issue