Skip to content

Commit 8460ef8

Browse files
authored
Add TSDoc support (#55)
* Add comment support * Update docs
1 parent edd5ad7 commit 8460ef8

File tree

9 files changed

+55
-22
lines changed

9 files changed

+55
-22
lines changed

docs/src/content/docs/component.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ title: Writing Components
77
Here's the basic structure of a MistCSS component. See below for details.
88

99
```css title="Button.mist.css" copy
10-
/* Tag and component name */
10+
/* This comment will be used as TSDoc for the generated component. */
1111
@scope (button.custom-button) {
1212
:scope {
1313
/* CSS variables */

src/parser.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ import { test, expect } from 'vitest'
22

33
import { parse } from './parser.js'
44

5-
test('parse', () => {
5+
test('parse', () => {
66
const css = `
7+
/* comment */
78
@scope (div.foo) {
89
:scope {
910
--foo: green;
@@ -26,6 +27,7 @@ import { parse } from './parser.js'
2627
const actual = parse(css)
2728
const expected = [
2829
{
30+
comment: 'comment',
2931
tag: 'div',
3032
className: 'foo',
3133
attributes: { 'data-foo': new Set(['one', 'two']) },

src/parser.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,31 @@ import {
44
Element,
55
Middleware,
66
middleware,
7+
COMMENT,
78
RULESET,
89
// @ts-ignore
910
SCOPE,
1011
serialize,
1112
} from 'stylis'
1213

1314
export interface Data {
15+
comment: string
1416
className: string // foo
1517
tag: string // div
1618
attributes: Record<string, Set<string>> // data-foo: ['bar', 'baz']
1719
booleanAttributes: Set<string> // data-foo, data-bar
1820
properties: Set<string> // --foo, --bar
1921
}
2022

23+
function getComment(element: Element): string {
24+
// @ts-ignore
25+
const prev = element.siblings[element.siblings.indexOf(element) - 1] as Element
26+
if (prev.type === COMMENT) {
27+
return (prev.children as string).trim()
28+
}
29+
return ''
30+
}
31+
2132
// (div.foo) -> { tag: 'div', className: 'foo' }
2233
function parseScopeSelector(str: string): { tag: string; className: string } {
2334
const [tag = '', className = ''] = str.slice(1, -1).split('.')
@@ -38,7 +49,7 @@ function parseAttribute(str: string): { attribute: string; value?: string } {
3849
}
3950

4051
function update(data: Data): Middleware {
41-
return function (element, _index, _children, callback) {
52+
return function(element, _index, _children, callback) {
4253
switch (element.type) {
4354
case DECLARATION:
4455
// Custom properties
@@ -48,7 +59,7 @@ function update(data: Data): Middleware {
4859
break
4960

5061
case RULESET:
51-
;(element.props as string[])
62+
; (element.props as string[])
5263
.filter(isAttribute)
5364
.map(parseAttribute)
5465
.forEach(({ attribute, value }) => {
@@ -81,6 +92,7 @@ export function parse(css: string): Data[] {
8192
const { tag, className } = parseScopeSelector(prop)
8293

8394
const data: Data = {
95+
comment: getComment(element),
8496
tag,
8597
className,
8698
attributes: {},

src/renderers/__snapshots__/react.test.ts.snap

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import type { PropsWithChildren } from 'hono/jsx'
88
99
type Props = { attr?: 'a' | 'b', attrFooBar?: 'foo-bar', isFoo?: boolean, propFoo?: string, propBar?: string } & JSX.IntrinsicElements['div']
1010
11+
/**
12+
* comment
13+
*/
1114
export function Foo({ children, attr, attrFooBar, isFoo, propFoo, propBar, ...props }: PropsWithChildren<Props>) {
1215
return (<div {...props} data-attr={attr} data-attr-foo-bar={attrFooBar} data-is-foo={isFoo} style={{ '--prop-foo': propFoo, '--prop-bar': propBar }} class="foo" >{children}</div>)
1316
}
@@ -22,6 +25,9 @@ import type { JSX, PropsWithChildren } from 'react'
2225
2326
type Props = { attr?: 'a' | 'b', attrFooBar?: 'foo-bar', isFoo?: boolean, propFoo?: string, propBar?: string } & JSX.IntrinsicElements['div']
2427
28+
/**
29+
* comment
30+
*/
2531
export function Foo({ children, attr, attrFooBar, isFoo, propFoo, propBar, ...props }: PropsWithChildren<Props>) {
2632
return (<div {...props} data-attr={attr} data-attr-foo-bar={attrFooBar} data-is-foo={isFoo} style={{ '--prop-foo': propFoo, '--prop-bar': propBar }} className="foo" >{children}</div>)
2733
}
@@ -36,6 +42,9 @@ import type { JSX, PropsWithChildren } from 'react'
3642
3743
type Props = { } & JSX.IntrinsicElements['div']
3844
45+
/**
46+
* comment
47+
*/
3948
export function Foo({ children, ...props }: PropsWithChildren<Props>) {
4049
return (<div {...props} className="foo" >{children}</div>)
4150
}
@@ -50,6 +59,9 @@ import type { JSX } from 'react'
5059
5160
type Props = { } & JSX.IntrinsicElements['hr']
5261
62+
/**
63+
* comment
64+
*/
5365
export function Foo({ ...props }: Props) {
5466
return (<hr {...props} className="foo" />)
5567
}

src/renderers/__snapshots__/vue.test.ts.snap

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import type { JSX } from 'vue/jsx-runtime'
1010
1111
type Props = { attr?: 'a' | 'b', attrFooBar?: 'foo-bar', isFoo?: boolean, propFoo?: string, propBar?: string } & JSX.IntrinsicElements['div']
1212
13+
/**
14+
* comment
15+
*/
1316
export function Foo({ attr, attrFooBar, isFoo, propFoo, propBar, ...props }: Props, { slots }: SetupContext) {
1417
return (<div {...props} data-attr={attr} data-attr-foo-bar={attrFooBar} data-is-foo={isFoo} style={{ '--prop-foo': propFoo, '--prop-bar': propBar }} class="foo" >{slots.default?.()}</div>)
1518
}
@@ -26,6 +29,9 @@ import type { JSX } from 'vue/jsx-runtime'
2629
2730
type Props = { } & JSX.IntrinsicElements['div']
2831
32+
/**
33+
* comment
34+
*/
2935
export function Foo({ ...props }: Props, { slots }: SetupContext) {
3036
return (<div {...props} class="foo" >{slots.default?.()}</div>)
3137
}
@@ -42,6 +48,9 @@ import type { JSX } from 'vue/jsx-runtime'
4248
4349
type Props = { } & JSX.IntrinsicElements['hr']
4450
51+
/**
52+
* comment
53+
*/
4554
export function Foo({ ...props }: Props) {
4655
return (<hr {...props} class="foo" />)
4756
}

src/renderers/react.test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { render } from './react.js'
66
describe('render', () => {
77
it('renders React component (full)', () => {
88
const data: Data = {
9+
comment: 'comment',
910
tag: 'div',
1011
className: 'foo',
1112
attributes: {
@@ -22,6 +23,7 @@ describe('render', () => {
2223

2324
it('renders React component (minimal)', () => {
2425
const data: Data = {
26+
comment: 'comment',
2527
tag: 'div',
2628
className: 'foo',
2729
attributes: {},
@@ -35,6 +37,7 @@ describe('render', () => {
3537

3638
it('renders React component (void element)', () => {
3739
const data: Data = {
40+
comment: 'comment',
3841
tag: 'hr', // hr is a void element and should not have children
3942
className: 'foo',
4043
attributes: {},
@@ -48,6 +51,7 @@ describe('render', () => {
4851

4952
it('renders Hono component (full)', () => {
5053
const data: Data = {
54+
comment: 'comment',
5155
tag: 'div',
5256
className: 'foo',
5357
attributes: {
@@ -62,4 +66,4 @@ describe('render', () => {
6266
const result = render('component', data, isHono)
6367
expect(result).toMatchSnapshot()
6468
})
65-
})
69+
})

src/renderers/react.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ function renderFunction(data: Data, isClass: boolean): string {
3131
'...props',
3232
].join(', ')
3333

34-
return `export function ${pascalCase(data.className)}({ ${args} }: ${hasChildren(data.tag) ? `PropsWithChildren<Props>` : `Props`}) {
34+
return `/**
35+
* ${data.comment}
36+
*/
37+
export function ${pascalCase(data.className)}({ ${args} }: ${hasChildren(data.tag) ? `PropsWithChildren<Props>` : `Props`}) {
3538
return (${renderTag(data, '{children}', isClass ? 'class' : 'className')})
3639
}`
3740
}

src/renderers/vue.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { render } from './vue.js'
66
describe('render', () => {
77
it('renders Vue component (full)', () => {
88
const data: Data = {
9+
comment: 'comment',
910
tag: 'div',
1011
className: 'foo',
1112
attributes: {
@@ -22,6 +23,7 @@ describe('render', () => {
2223

2324
it('renders Vue component (minimal)', () => {
2425
const data: Data = {
26+
comment: 'comment',
2527
tag: 'div',
2628
className: 'foo',
2729
attributes: {},
@@ -35,6 +37,7 @@ describe('render', () => {
3537

3638
it('renders Vue component (void element)', () => {
3739
const data: Data = {
40+
comment: 'comment',
3841
tag: 'hr', // hr is a void element and should not have children
3942
className: 'foo',
4043
attributes: {},

src/renderers/vue.ts

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,3 @@
1-
// import type { SetupContext } from 'vue'
2-
// import type { JSX } from 'vue/jsx-runtime'
3-
4-
// type FComponentProps = {
5-
// message?: string
6-
// } & JSX.IntrinsicElements['img']
7-
8-
// export default function FComponent(props: FComponentProps, context: SetupContext) {
9-
// return (
10-
// <img {...props} class="foo">
11-
// {context.slots.default?.()}
12-
// </img>
13-
// )
14-
// }
15-
161
import { attributeToCamelCase, pascalCase, propertyToCamelCase } from './_case.js'
172
import { Data } from '../parser.js'
183
import { renderTag, renderPropsInterface, hasChildren } from './_common.js'
@@ -25,7 +10,10 @@ function renderFunction(data: Data): string {
2510
'...props',
2611
].join(', ')
2712

28-
return `export function ${pascalCase(data.className)}({ ${args} }: Props${hasChildren(data.tag) ? ', { slots }: SetupContext' : ''}) {
13+
return `/**
14+
* ${data.comment}
15+
*/
16+
export function ${pascalCase(data.className)}({ ${args} }: Props${hasChildren(data.tag) ? ', { slots }: SetupContext' : ''}) {
2917
return (${renderTag(data, '{slots.default?.()}', 'class')})
3018
}`
3119
}

0 commit comments

Comments
 (0)