Skip to content

Commit

Permalink
add Template parser
Browse files Browse the repository at this point in the history
  • Loading branch information
HcySunYang committed Oct 6, 2018
1 parent 611af52 commit 6674f2a
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 3 deletions.
19 changes: 19 additions & 0 deletions __fixtures__/defaultSlot.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<template>
<div>
<!-- default slot -->
<slot>
<!-- Default Slot Content -->
<p></p>
</slot>
</div>
</template>

<script>
export default {
}
</script>

<style>
</style>
19 changes: 19 additions & 0 deletions __fixtures__/namedSlot.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<template>
<div>
<!-- head slot -->
<slot name="header">
<!-- Default Slot Content -->
<p></p>
</slot>
</div>
</template>

<script>
export default {
}
</script>

<style>
</style>
19 changes: 19 additions & 0 deletions __fixtures__/slotWithBindings.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<template>
<div>
<!-- Named slot -->
<slot name="header" :a="someData" b="str">
<!-- Default Slot Content -->
<p></p>
</slot>
</div>
</template>

<script>
export default {
}
</script>

<style>
</style>
43 changes: 43 additions & 0 deletions src/parse/__test__/parseTemplate.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import * as path from 'path'
import * as fs from 'fs'
import sfcToAST, { AstResult } from '../sfcToAST'
import parseTemplate, { SlotResult } from '../parseTemplate'

function getAST(fileName: string): object {
const p = path.resolve(__dirname, `../../../__fixtures__/${fileName}`)
const source = fs.readFileSync(p, 'utf-8')
return sfcToAST(source)
}

test('Default slot with slot description', () => {
const sfc: AstResult = getAST('defaultSlot.vue')
const slotRes: SlotResult[] = parseTemplate(sfc.templateAst)
expect(slotRes.length).toBe(1)
expect(slotRes[0].name).toBe('default')
expect(slotRes[0].describe).toBe('default slot')
expect(slotRes[0].backerDesc).toBe('Default Slot Content')
expect(slotRes[0].bindings).toEqual({})
})

test('Named slot with slot description', () => {
const sfc: AstResult = getAST('namedSlot.vue')
const slotRes: SlotResult[] = parseTemplate(sfc.templateAst)
expect(slotRes.length).toBe(1)
expect(slotRes[0].name).toBe('header')
expect(slotRes[0].describe).toBe('head slot')
expect(slotRes[0].backerDesc).toBe('Default Slot Content')
expect(slotRes[0].bindings).toEqual({})
})

test('Named slot with slot description and bingdings', () => {
const sfc: AstResult = getAST('slotWithBindings.vue')
const slotRes: SlotResult[] = parseTemplate(sfc.templateAst)
expect(slotRes.length).toBe(1)
expect(slotRes[0].name).toBe('header')
expect(slotRes[0].describe).toBe('Named slot')
expect(slotRes[0].backerDesc).toBe('Default Slot Content')
expect(slotRes[0].bindings).toEqual({
a: 'someData',
b: 'str'
})
})
4 changes: 4 additions & 0 deletions src/parse/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import sfcToAST from './sfcToAST'
import parseJavascript from './parseJavascript'
import parseTemplate from './parseTemplate'

export type PropType = string | string[] | null

Expand All @@ -26,4 +27,7 @@ export default function(source: string, options: ParserOptions) {
if (astRes.jsAst) {
parseJavascript(astRes.jsAst, options)
}
if (astRes.templateAst) {
parseTemplate(astRes.templateAst)
}
}
File renamed without changes.
2 changes: 1 addition & 1 deletion src/parse/parseJavascript.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import traverse from '@babel/traverse'
import generate from '@babel/generator'
import * as bt from '@babel/types'
import { getComments } from './comments'
import { getComments } from './jscomments'
import { PropsResult, PropType, ParserOptions } from './index'
import { getValueFromGenerate, isPropsOption, runFunction } from '../helpers'
import { isArray } from 'util'
Expand Down
87 changes: 85 additions & 2 deletions src/parse/parseTemplate.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,86 @@
import { parse } from 'vue-template-compiler'
export interface SlotResult {
name: string
describe: string
backerDesc: string
bindings: AttrsMap
}

export default function() {}
export default function traverse(templateAst: any): SlotResult[] {
const parent = templateAst.parent
let res: SlotResult[] = []
if (templateAst.type === 1) {
if (templateAst.tag === 'slot') {
const slot: SlotResult = {
name: 'default',
describe: '',
backerDesc: '',
bindings: {}
}
slot.bindings = extractAndFilterAttr(templateAst.attrsMap)
if (slot.bindings.name) {
slot.name = slot.bindings.name
delete slot.bindings.name
}
if (parent) {
const list: [] = parent.children
let currentSlotIndex = 0
for (let i = 0; i < list.length; i++) {
let el = list[i]
if (el === templateAst) {
currentSlotIndex = i
break
}
}

// Find the first leading comment node as a description of the slot
const copies = list.slice(0, currentSlotIndex).reverse()
for (let i = 0; i < copies.length; i++) {
let el: any = copies[i]
if (el.type !== 3 || (!el.isComment && el.text.trim())) break
if (
el.isComment &&
!(parent.tag === 'slot' && parent.children[0] === el)
) {
slot.describe = el.text.trim()
break
}
}

// Find the first child comment node as a description of the default slot content
if (templateAst.children.length) {
for (let i = 0; i < templateAst.children.length; i++) {
let el: any = templateAst.children[i]
if (el.type !== 3 || (!el.isComment && el.text.trim())) break
if (el.isComment) {
slot.backerDesc = el.text.trim()
break
}
}
}
}
res.push(slot)
}
for (let i = 0; i < templateAst.children.length; i++) {
res = res.concat(traverse(templateAst.children[i]))
}
}

return res
}

type AttrsMap = {
[key: string]: string
}
const dirRE = /^(v-|:|@)/
const allowRE = /^(v-bind|:)/
function extractAndFilterAttr(attrsMap: AttrsMap): AttrsMap {
const res: AttrsMap = {}
const keys = Object.keys(attrsMap)
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
if (!dirRE.test(key) || allowRE.test(key)) {
res[key.replace(allowRE, '')] = attrsMap[key]
}
}
return res
}

0 comments on commit 6674f2a

Please sign in to comment.