Skip to content

Commit

Permalink
Merge pull request #4 from jackkoppa/feature/finalize-supported-options
Browse files Browse the repository at this point in the history
Implement parsing for events & slots; improve formatting across cases
  • Loading branch information
jackkoppa authored Jan 6, 2020
2 parents 77ff2a3 + b9c27e6 commit 3d8258a
Show file tree
Hide file tree
Showing 8 changed files with 529 additions and 23 deletions.
Binary file added .DS_Store
Binary file not shown.
Binary file modified docs/example_snippet.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
398 changes: 392 additions & 6 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"@types/node": "^12.7.5",
"@typescript-eslint/eslint-plugin": "^2.3.0",
"@typescript-eslint/parser": "^2.3.0",
"@zeplin/cli": "^0.1.1",
"@zeplin/cli": "^0.3.1",
"@zeplin/eslint-config": "^2.2.0",
"eslint": "^6.4.0",
"eslint-import-resolver-typescript": "^2.0.0",
Expand All @@ -48,6 +48,8 @@
"vue": "^2.6.10"
},
"dependencies": {
"param-case": "^3.0.3",
"pascal-case": "^3.1.1",
"vue-docgen-api": "^4.1.1"
}
}
86 changes: 75 additions & 11 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { ConnectPlugin, ComponentConfig, ComponentData, PrismLang } from "@zeplin/cli"
import { parse } from 'vue-docgen-api'
import { paramCase } from "param-case";
import { pascalCase } from "pascal-case";
import { parse, ComponentDoc } from 'vue-docgen-api'
import path from "path";

export default class implements ConnectPlugin {
Expand All @@ -16,17 +18,79 @@ export default class implements ConnectPlugin {

const componentInfo = await parse(context.path)

const description = componentInfo.description
const { description, displayName } = componentInfo

const propsBlock = componentInfo.props && componentInfo.props.map(prop => {
return `${prop.name}="${prop.type && prop.type.name || 'unknown'}"`
}) || []

/** @TODO Determine if we need pug or other templating tools to help with things like slots & events */
const snippet =
`<${componentInfo.displayName}
${propsBlock.join('\n ')}
/>`
const propLines = this.getPropLines(componentInfo)

const eventLines = this.getEventLines(componentInfo)

const slotLines = this.getSlotLines(componentInfo)

const snippet = this.generateSnippet(displayName, propLines, eventLines, slotLines)

return { description, snippet, lang };
}

getPropLines(componentInfo: ComponentDoc): string[] {
return componentInfo.props && componentInfo.props.map(prop =>
`${paramCase(prop.name)}="${prop.type && prop.type.name || 'unknown'}"`
) || []
}

getSlotLines(componentInfo: ComponentDoc): string[] {
return componentInfo.slots && componentInfo.slots.map(slot => {
if (slot.name === 'default') return `<!-- content -->`

if (slot.scoped) {
let slotBinding = 'scopedBinding'
if (slot.bindings && slot.bindings[0] && slot.bindings[0].name) slotBinding = slot.bindings[0].name
return `<template #${slot.name}="${slotBinding}"></template>`
}

return `<template #${slot.name}></template>`
}) || []
}

getEventLines(componentInfo: ComponentDoc): string[] {
return componentInfo.events && componentInfo.events.map(event => {
return `@${event.name}="handle${pascalCase(event.name)}"`
}) || []
}

generateSnippet(displayName: string, propLines: string[], eventLines: string[], slotLines: string[]): string {
let snippet =''

const combinedPropEventLines = [...propLines, ...eventLines]

if (!combinedPropEventLines.length && !slotLines.length) {

snippet = `<${displayName} />`

} else if (combinedPropEventLines.length && !slotLines.length) {

snippet =
`<${displayName}
${combinedPropEventLines.join('\n ')}
/>`

} else if (!combinedPropEventLines.length && slotLines.length) {

snippet =
`<${displayName}>
${slotLines.join('\n ')}
</${displayName}>`

} else {

snippet =
`<${displayName}
${combinedPropEventLines.join('\n ')}
>
${slotLines.join('\n ')}
</${displayName}>`

}

return snippet
}
}
27 changes: 22 additions & 5 deletions test/__snapshots__/index.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,28 @@
exports[`Connected Components Vue Plugin MyButton.vue snippet creation 1`] = `
Object {
"description": "General component description",
"lang": "jsx",
"lang": "html",
"snippet": "<MyButton
color=\\"string\\"
disabled=\\"boolean\\"
href=\\"string\\"
icon=\\"string\\"
iconPlacement=\\"string\\"
iconProps=\\"object\\"
icon-placement=\\"string\\"
icon-props=\\"object\\"
label=\\"string\\"
size=\\"string\\"
to=\\"string|object\\"
/>",
@click=\\"handleClick\\"
>
<!-- content -->
</MyButton>",
}
`;

exports[`Connected Components Vue Plugin MyIcon.vue snippet creation 1`] = `
Object {
"description": "General component description",
"lang": "jsx",
"lang": "html",
"snippet": "<MyIcon
name=\\"string\\"
width=\\"number\\"
Expand All @@ -31,3 +34,17 @@ Object {
/>",
}
`;

exports[`Connected Components Vue Plugin MyLightweightComponent.vue snippet creation 1`] = `
Object {
"description": "",
"lang": "html",
"snippet": "<MyLightweightComponent
simple-prop=\\"string\\"
@simple-event=\\"handleSimpleEvent\\"
>
<!-- content -->
<template #simpleSlot=\\"slotBinding\\"></template>
</MyLightweightComponent>",
}
`;
13 changes: 13 additions & 0 deletions test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,17 @@ describe("Connected Components Vue Plugin", () => {

expect(componentCode).toMatchSnapshot();
});

test("MyLightweightComponent.vue snippet creation", async () => {
const processor = new Plugin();

const componentCode = await processor.process(
{
path: "test/samples/MyLightweightComponent.vue",
zeplinNames: []
}
);

expect(componentCode).toMatchSnapshot();
});
});
24 changes: 24 additions & 0 deletions test/samples/MyLightweightComponent.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<script>
export default {
name: 'MyLightweightComponent',
props: {
simpleProp: {
type: String,
default: 'some string'
}
},
methods: {
emitSimpleEvent(event) {
this.$emit('simple-event', event)
}
}
}
</script>

<template>
<div>
<slot>Default content for default slot</slot>
<slot name="simpleSlot" :slotBinding="slotBinding">{{ slotBinding.someValue }}</slot>
<button @click="emitSimpleEvent">Simple Button</button>
</div>
</template>

0 comments on commit 3d8258a

Please sign in to comment.