katashin
6 years ago
committed by
Evan You
4 changed files with 298 additions and 0 deletions
@ -0,0 +1,221 @@ |
|||
import Vue, { VNode } from "vue" |
|||
|
|||
/* |
|||
* Template compilation options / results |
|||
*/ |
|||
interface CompilerOptions { |
|||
modules?: ModuleOptions[]; |
|||
directives?: Record<string, DirectiveFunction>; |
|||
preserveWhitespace?: boolean; |
|||
} |
|||
|
|||
interface CompiledResult { |
|||
ast: ASTElement | undefined; |
|||
render: string; |
|||
staticRenderFns: string[]; |
|||
errors: string[]; |
|||
tips: string[]; |
|||
} |
|||
|
|||
interface CompiledResultFunctions { |
|||
render: () => VNode; |
|||
staticRenderFns: (() => VNode)[]; |
|||
} |
|||
|
|||
interface ModuleOptions { |
|||
preTransformNode: (el: ASTElement) => ASTElement | undefined; |
|||
transformNode: (el: ASTElement) => ASTElement | undefined; |
|||
postTransformNode: (el: ASTElement) => void; |
|||
genData: (el: ASTElement) => string; |
|||
transformCode?: (el: ASTElement, code: string) => string; |
|||
staticKeys?: string[]; |
|||
} |
|||
|
|||
type DirectiveFunction = (node: ASTElement, directiveMeta: ASTDirective) => void; |
|||
|
|||
/* |
|||
* AST Types |
|||
*/ |
|||
|
|||
/** |
|||
* - 0: FALSE - whole sub tree un-optimizable |
|||
* - 1: FULL - whole sub tree optimizable |
|||
* - 2: SELF - self optimizable but has some un-optimizable children |
|||
* - 3: CHILDREN - self un-optimizable but have fully optimizable children |
|||
* - 4: PARTIAL - self un-optimizable with some un-optimizable children |
|||
*/ |
|||
export type SSROptimizability = 0 | 1 | 2 | 3 | 4 |
|||
|
|||
export interface ASTModifiers { |
|||
[key: string]: boolean; |
|||
} |
|||
|
|||
export interface ASTIfCondition { |
|||
exp: string | undefined; |
|||
block: ASTElement; |
|||
} |
|||
|
|||
export interface ASTElementHandler { |
|||
value: string; |
|||
params?: any[]; |
|||
modifiers: ASTModifiers | undefined; |
|||
} |
|||
|
|||
export interface ASTElementHandlers { |
|||
[key: string]: ASTElementHandler | ASTElementHandler[]; |
|||
} |
|||
|
|||
export interface ASTDirective { |
|||
name: string; |
|||
rawName: string; |
|||
value: string; |
|||
arg: string | undefined; |
|||
modifiers: ASTModifiers | undefined; |
|||
} |
|||
|
|||
export type ASTNode = ASTElement | ASTText | ASTExpression; |
|||
|
|||
export interface ASTElement { |
|||
type: 1; |
|||
tag: string; |
|||
attrsList: { name: string; value: any }[]; |
|||
attrsMap: Record<string, any>; |
|||
parent: ASTElement | undefined; |
|||
children: ASTNode[]; |
|||
|
|||
processed?: true; |
|||
|
|||
static?: boolean; |
|||
staticRoot?: boolean; |
|||
staticInFor?: boolean; |
|||
staticProcessed?: boolean; |
|||
hasBindings?: boolean; |
|||
|
|||
text?: string; |
|||
attrs?: { name: string; value: any }[]; |
|||
props?: { name: string; value: string }[]; |
|||
plain?: boolean; |
|||
pre?: true; |
|||
ns?: string; |
|||
|
|||
component?: string; |
|||
inlineTemplate?: true; |
|||
transitionMode?: string | null; |
|||
slotName?: string; |
|||
slotTarget?: string; |
|||
slotScope?: string; |
|||
scopedSlots?: Record<string, ASTElement>; |
|||
|
|||
ref?: string; |
|||
refInFor?: boolean; |
|||
|
|||
if?: string; |
|||
ifProcessed?: boolean; |
|||
elseif?: string; |
|||
else?: true; |
|||
ifConditions?: ASTIfCondition[]; |
|||
|
|||
for?: string; |
|||
forProcessed?: boolean; |
|||
key?: string; |
|||
alias?: string; |
|||
iterator1?: string; |
|||
iterator2?: string; |
|||
|
|||
staticClass?: string; |
|||
classBinding?: string; |
|||
staticStyle?: string; |
|||
styleBinding?: string; |
|||
events?: ASTElementHandlers; |
|||
nativeEvents?: ASTElementHandlers; |
|||
|
|||
transition?: string | true; |
|||
transitionOnAppear?: boolean; |
|||
|
|||
model?: { |
|||
value: string; |
|||
callback: string; |
|||
expression: string; |
|||
}; |
|||
|
|||
directives?: ASTDirective[]; |
|||
|
|||
forbidden?: true; |
|||
once?: true; |
|||
onceProcessed?: boolean; |
|||
wrapData?: (code: string) => string; |
|||
wrapListeners?: (code: string) => string; |
|||
|
|||
// 2.4 ssr optimization
|
|||
ssrOptimizability?: SSROptimizability; |
|||
|
|||
// weex specific
|
|||
appendAsTree?: boolean; |
|||
} |
|||
|
|||
export interface ASTExpression { |
|||
type: 2; |
|||
expression: string; |
|||
text: string; |
|||
tokens: (string | Record<string, any>)[]; |
|||
static?: boolean; |
|||
// 2.4 ssr optimization
|
|||
ssrOptimizability?: SSROptimizability; |
|||
} |
|||
|
|||
export interface ASTText { |
|||
type: 3; |
|||
text: string; |
|||
static?: boolean; |
|||
isComment?: boolean; |
|||
// 2.4 ssr optimization
|
|||
ssrOptimizability?: SSROptimizability; |
|||
} |
|||
|
|||
/* |
|||
* SFC parser related types |
|||
*/ |
|||
interface SFCParserOptions { |
|||
pad?: true | 'line' | 'space'; |
|||
} |
|||
|
|||
export interface SFCBlock { |
|||
type: string; |
|||
content: string; |
|||
attrs: Record<string, string>; |
|||
start?: number; |
|||
end?: number; |
|||
lang?: string; |
|||
src?: string; |
|||
scoped?: boolean; |
|||
module?: string | boolean; |
|||
} |
|||
|
|||
export interface SFCDescriptor { |
|||
template: SFCBlock | undefined; |
|||
script: SFCBlock | undefined; |
|||
styles: SFCBlock[]; |
|||
customBlocks: SFCBlock[]; |
|||
} |
|||
|
|||
/* |
|||
* Exposed functions |
|||
*/ |
|||
export function compile( |
|||
template: string, |
|||
options?: CompilerOptions |
|||
): CompiledResult; |
|||
|
|||
export function compileToFunctions(template: string): CompiledResultFunctions; |
|||
|
|||
export function ssrCompile( |
|||
template: string, |
|||
options?: CompilerOptions |
|||
): CompiledResult; |
|||
|
|||
export function ssrCompileToFunctions(template: string): CompiledResultFunctions; |
|||
|
|||
export function parseComponent( |
|||
file: string, |
|||
options?: SFCParserOptions |
|||
): SFCDescriptor; |
@ -0,0 +1,60 @@ |
|||
import Vue, { VNode } from "vue"; |
|||
import { |
|||
compile, |
|||
compileToFunctions, |
|||
ssrCompile, |
|||
ssrCompileToFunctions, |
|||
parseComponent |
|||
} from "./"; |
|||
|
|||
// check compile options
|
|||
const compiled = compile("<div>hi</div>", { |
|||
preserveWhitespace: false, |
|||
modules: [ |
|||
{ |
|||
preTransformNode: el => el, |
|||
transformNode: el => el, |
|||
postTransformNode: el => { |
|||
el.tag = "p"; |
|||
}, |
|||
genData: el => el.tag, |
|||
transformCode: (el, code) => code, |
|||
staticKeys: ["test"] |
|||
} |
|||
], |
|||
directives: { |
|||
test: (node, directiveMeta) => { |
|||
node.tag; |
|||
directiveMeta.value; |
|||
} |
|||
} |
|||
}); |
|||
|
|||
// can be passed to function constructor
|
|||
new Function(compiled.render); |
|||
compiled.staticRenderFns.map(fn => new Function(fn)); |
|||
|
|||
const compiledFns = compileToFunctions("<div>hi</div>"); |
|||
|
|||
// can be passed to component render / staticRenderFns options
|
|||
const vm = new Vue({ |
|||
data() { |
|||
return { |
|||
test: "Test" |
|||
}; |
|||
}, |
|||
render: compiledFns.render, |
|||
staticRenderFns: compiledFns.staticRenderFns |
|||
}); |
|||
|
|||
// can be called with component instance
|
|||
const vnode: VNode = compiledFns.render.call(vm); |
|||
|
|||
// check SFC parser
|
|||
const desc = parseComponent("<template></template>", { |
|||
pad: "space" |
|||
}); |
|||
|
|||
const templateContent: string = desc.template!.content; |
|||
const scriptContent: string = desc.script!.content; |
|||
const styleContent: string = desc.styles.map(s => s.content).join("\n"); |
@ -0,0 +1,13 @@ |
|||
{ |
|||
"compilerOptions": { |
|||
"target": "es5", |
|||
"module": "commonjs", |
|||
"moduleResolution": "node", |
|||
"strict": true, |
|||
"noEmit": true |
|||
}, |
|||
"compileOnSave": false, |
|||
"include": [ |
|||
"**/*.ts" |
|||
] |
|||
} |
Loading…
Reference in new issue