diff --git a/packages/vue-template-compiler/package.json b/packages/vue-template-compiler/package.json index 7ef9b437835..52c83f31358 100644 --- a/packages/vue-template-compiler/package.json +++ b/packages/vue-template-compiler/package.json @@ -6,6 +6,7 @@ "unpkg": "browser.js", "jsdelivr": "browser.js", "browser": "browser.js", + "types": "types/index.d.ts", "repository": { "type": "git", "url": "git+https://github.com/vuejs/vue.git" @@ -23,5 +24,8 @@ "dependencies": { "he": "^1.1.0", "de-indent": "^1.0.2" + }, + "devDependencies": { + "vue": "file:../.." } } diff --git a/packages/vue-template-compiler/types/index.d.ts b/packages/vue-template-compiler/types/index.d.ts new file mode 100644 index 00000000000..0d1c810ba3f --- /dev/null +++ b/packages/vue-template-compiler/types/index.d.ts @@ -0,0 +1,221 @@ +import Vue, { VNode } from "vue" + +/* + * Template compilation options / results + */ +interface CompilerOptions { + modules?: ModuleOptions[]; + directives?: Record; + 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; + 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; + + 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)[]; + 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; + 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; diff --git a/packages/vue-template-compiler/types/test.ts b/packages/vue-template-compiler/types/test.ts new file mode 100644 index 00000000000..be00815c78f --- /dev/null +++ b/packages/vue-template-compiler/types/test.ts @@ -0,0 +1,60 @@ +import Vue, { VNode } from "vue"; +import { + compile, + compileToFunctions, + ssrCompile, + ssrCompileToFunctions, + parseComponent +} from "./"; + +// check compile options +const compiled = compile("
hi
", { + 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("
hi
"); + +// 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("", { + 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"); diff --git a/packages/vue-template-compiler/types/tsconfig.json b/packages/vue-template-compiler/types/tsconfig.json new file mode 100644 index 00000000000..084dd317ea1 --- /dev/null +++ b/packages/vue-template-compiler/types/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "strict": true, + "noEmit": true + }, + "compileOnSave": false, + "include": [ + "**/*.ts" + ] +}