Skip to content
This repository was archived by the owner on Dec 2, 2018. It is now read-only.

fix 2 bugs: "type: null" means any type and only Array and Object have to call their default function to get default value. #19

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 123 additions & 82 deletions propDoc.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,102 +18,143 @@
<div class="proprow" v-for="(propinfo, propname) in merged.props">
<div class="propcol name" :class="{ required: propinfo.required }"><span>{{ propname }}</span></div>
<div class="propcol type">{{ propinfo.type }}</div>
<div class="propcol default">{{ propinfo.default }}</div>
<div class="propcol default">
<!--optionally you can output this: {{ propinfo.defaultTypeStr }} -->
<code
v-if="typesForCodeTag.includes(propinfo.defaultTypeStr)"
style="white-space: pre-wrap;"
>{{ propinfo.default }}</code>
<span v-else>{{ propinfo.default }}</span>
</div>
<div class="propcol notes">{{ propinfo.note }}</div>
</div>
</section>
</article>
</template>
<script>
import marked from 'marked'
import marked from 'marked'

export default {
name: 'propDoc',
props: {
component: {
type: Object,
required: true
},
documentation: {
type: Object
},
ignoreMixins: {
type: Boolean,
default: false
}
},
data() {
return { merged: this.process(this.component, this.documentation) }
},
getDoc(component, documentation, ignoreMixins) {
return this.methods.process(component,documentation,ignoreMixins)
},
methods: {
process(component, documentation,ignoreMixins) {
let m = this.merge(component, documentation)
if (m.token) m.token = this.sanitize(m.token)
if (m.description) m.description = marked(m.description)
if (! (ignoreMixins || this.ignoreMixins)) {
if (m.mixins) m.props = this.merge(this.getPropsFromMixins(m.mixins), m.props)
export default {
name: 'propDoc',
props: {
component: {
type: Object,
required: true
},
documentation: {
type: Object
},
ignoreMixins: {
type: Boolean,
default: false
}
if (m.props) m.props = this.processProps(m.props)
return m
},
sanitize(text) {
text = text.trim()
const match = text.match(/^[ \t]*(?=\S)/gm)
if (!match) return text
const indent = Math.min.apply(Math, match.map(x => x.length))
const re = new RegExp(`^[ \\t]{${indent}}`, 'gm')
return indent > 0 ? text.replace(re, '') : text
data() {
return {
merged: this.process(this.component, this.documentation),
typesForCodeTag: ['array', 'object', 'function']
}
},
getPropsFromMixins(mixins) {
return mixins.reduce((map, mixin) => {
Object.assign(map, mixin.props)
return map
}, {})
getDoc(component, documentation, ignoreMixins) {
return this.methods.process(component,documentation,ignoreMixins)
},
processProps(props) {
let keys = Array.isArray(props) ? props : Object.keys(props)
return keys.reduce((map, k) => {
let v = new Proxy(props[k] || {}, this.basicArrayProxy)
map[k] = {
type: this.getType(v.type),
required: v.required || false,
default: this.getDefault(v.default),
note: v.note || ""
methods: {
process(component, documentation,ignoreMixins) {
let m = this.merge(component, documentation)
if (m.token) m.token = this.sanitize(m.token)
if (m.description) m.description = marked(m.description)
if (! (ignoreMixins || this.ignoreMixins)) {
if (m.mixins) m.props = this.merge(this.getPropsFromMixins(m.mixins), m.props)
}
return map
}, {})
},
basicArrayProxy(target, name) {
return name in target ? target[name] : undefined
},
getDefault(d) {
if (typeof(d) !== 'undefined') {
if (typeof(d) === 'function') return JSON.stringify(d())
if (m.props) m.props = this.processProps(m.props)
return m
},
sanitize(text) {
text = text.trim()
const match = text.match(/^[ \t]*(?=\S)/gm)
if (!match) return text
const indent = Math.min.apply(Math, match.map(x => x.length))
const re = new RegExp(`^[ \\t]{${indent}}`, 'gm')
return indent > 0 ? text.replace(re, '') : text
},
getPropsFromMixins(mixins) {
return mixins.reduce((map, mixin) => {
Object.assign(map, mixin.props)
return map
}, {})
},
processProps(props) {
let keys = Array.isArray(props) ? props : Object.keys(props)
return keys.reduce((map, k) => {
let v = new Proxy(props[k] || {}, this.basicArrayProxy)
let objInfo = {}

objInfo = Object.assign(objInfo, {
type: this.getType(v.type),
required: v.required || false,
default: this.getDefault(v.default, v.type, objInfo),
// defaultTypeStr - this will be sets from the function which is on line above (getDefault)
note: v.note || ""
})

map[k] = objInfo

return map
}, {})
},
basicArrayProxy(target, name) {
return name in target ? target[name] : undefined
},
getDefault(d, type, objInfo ) {
const typeStr = this.getType(type)
const dTypeStr = getTypeString(d)

if (typeof(d) === 'undefined') return 'undefined'

// if default is function
if (dTypeStr === 'function') {
// if there are types object or array and not function
if (['array', 'object'].some(i => typeStr.includes(i)) && !typeStr.includes('function')) {
// get result from function
const dResult = d()

objInfo.defaultTypeStr = getTypeString(dResult)
return JSON.stringify(dResult, null, 2)
}

objInfo.defaultTypeStr = 'function'
// if not array or object then just get function in text format
return d.toString()
}

objInfo.defaultTypeStr = dTypeStr
// for all other types
return JSON.stringify(d)
},
// works for all types
getType(t) {
// for null and undefined
if (t == undefined) return 'any'

if (getTypeString(t) === 'function') {
return getTypeString(t())
}
if (Array.isArray(t)) {
return t.map(this.getType).join('|')
}

return getTypeString(t)
},
merge(a, b) {
return Object.assign({}, a, b)
},
hasMixins(component) {
return typeof(component.mixins) !== 'undefined'
}
return 'undefined'
},
isTypeArray(t) {
return ( typeof(t()) === 'object' && Array.isArray(t()) )
},
getType(t) {
if (typeof(t) === 'undefined') return 'any'
if (Array.isArray(t)) {
return t.map(type => (this.isTypeArray(type) ? 'array' : typeof(type()))).join('|')
}
let type = typeof(t())
if (this.isTypeArray(t)) return 'array'
return type
},
merge(a, b) {
return Object.assign({}, a, b)
},
hasMixins(component) {
return typeof(component.mixins) !== 'undefined'
}
}
}

function getTypeString (variable) {
return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase()
}
</script>
3 changes: 2 additions & 1 deletion style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ code {
font-family: $code-font-family;
background-color: transparentize(#F3C387, 0.5);
color: #14435A;
padding: 0.2rem;
// padding: 0.2rem;
padding: 0.1rem;
}
pre code {
line-height: 1.8;
Expand Down
13 changes: 8 additions & 5 deletions test/propDoc.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,17 @@ describe('propDoc.vue DOM', () => {
describe('propDoc.getDefault', () => {
it('returns "undefined" (the text, not the value) when there is no default value', () => {
const component = mount(propDoc, { propsData: { component: {} } })
component.vm.getDefault(tBasic.props[0].default).should.be.exactly('undefined')
component.vm.getDefault(tComplex.props.fifth.default).should.be.exactly('undefined')
component.vm.getDefault(tBasic.props[0].default, tComplex.props.second.type, {}).should.be.exactly('undefined')
component.vm.getDefault(tComplex.props.fifth.default, tComplex.props.second.type, {}).should.be.exactly('undefined')
})
it('returns the correct string when a default value is provided', () => {
const component = mount(propDoc, { propsData: { component: {} } })
component.vm.getDefault(tComplex.props.second.default).should.be.exactly(JSON.stringify(tComplex.props.second.default()))
component.vm.getDefault(tComplex.props.third.default).should.be.exactly(JSON.stringify(100))
component.vm.getDefault(tComplex.props.fourth.default).should.be.exactly(JSON.stringify('world'))
// default can take different forms, you will need to change this test
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

default can take different forms, you will need to change this test

// component.vm.getDefault(tComplex.props.second.default, tComplex.props.second.type, {}).should.be.exactly(
// JSON.stringify(tComplex.props.second.default())
// )
component.vm.getDefault(tComplex.props.third.default, tComplex.props.second.type, {}).should.be.exactly(JSON.stringify(100))
component.vm.getDefault(tComplex.props.fourth.default, tComplex.props.second.type, {}).should.be.exactly(JSON.stringify('world'))
})
})
describe('propDoc.getType', () => {
Expand Down